Change MULTITOP to warning to help linting, see manual.

This commit is contained in:
Wilson Snyder 2019-06-30 16:46:48 -04:00
parent 5f27c41ee3
commit f7641d2ecc
18 changed files with 329 additions and 84 deletions

View File

@ -4,6 +4,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.017 devel
*** Change MULTITOP to warning to help linting, see manual.
**** Show included-from filenames in warnings, bug1439. [Todd Strader]
**** Fix not reporting some duplicate signals/ports, bug1462. [Peter Gerst]

View File

@ -1280,7 +1280,7 @@ good value.
When the input Verilog contains more than one top level module, specifies
the name of the top level Verilog module to become the top, and sets the
default for if --prefix is not used. This is not needed with standard
designs with only one top.
designs with only one top. See also the MULTITOP warning section.
=item --trace
@ -3718,14 +3718,31 @@ correctly.
=item MULTITOP
Error that there are multiple top level modules, that is modules not
instantiated by any other module. Verilator only supports a single top
level, if you need more, create a module that wraps all of the top modules.
Warns that there are multiple top level modules, that is modules not
instantiated by any other module, and both modules were put on the command
line (not in a library). Three likely cases:
Often this error is because some low level cell is being read in, but is
not really needed. The best solution is to insure that each module is in a
unique file by the same name. Otherwise, make sure all library files are
read in as libraries with -v, instead of automatically with -y.
1. A single module is intended to be the top. This warning then occurs
because some low level cell is being read in, but is not really needed as
part of the design. The best solution for this situation is to ensure that
only the top module is put on the command line without any flags, and all
remaining library files are read in as libraries with -v, or are
automatically resolved by having filenames that match the module names.
2. A single module is intended to be the top, the name of it is known, and
all other modules should be ignored if not part of the design. The best
solution is to use the --top-module option to specify the top module's
name. All other modules that are not part of the design will be for the
most part ignored (they must be clean in syntax and their contents will be
removed as part of the Verilog module elaboration process.)
3. Multiple modules are intended to be design tops, e.g. when linting a
library file. As multiple modules are desired, disable the MULTITOP
warning. All input/outputs will go uniquely to each module, with any
conflicting and identical signal names being uniquified by adding a prefix
based on the top module name followed by __02E (a Verilator-encoded ASCII
".'). This renaming is done even if the two modules' signals seem
identical, e.g. multiple modules with a "clk" input.
=item PINCONNECTEMPTY

View File

@ -106,7 +106,7 @@ private:
//######################################################################
void V3CCtors::evalAsserts() {
AstNodeModule* modp = v3Global.rootp()->modulesp(); // Top module
AstNodeModule* modp = v3Global.rootp()->modulesp(); // Top module wrapper
AstCFunc* funcp = new AstCFunc(modp->fileline(), "_eval_debug_assertions", NULL, "void");
funcp->declPrivate(true);
funcp->isStatic(false);

View File

@ -49,7 +49,6 @@ public:
I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE)
// Error codes:
E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable
E_MULTITOP, // Error: Multiple top level modules
E_PORTSHORT, // Error: Output port is connected to a constant, electrical short
E_TASKNSVAR, // Error: Task I/O not simple
//
@ -89,6 +88,7 @@ public:
LITENDIAN, // Little bit endian vector
MODDUP, // Duplicate module
MULTIDRIVEN, // Driven from multiple blocks
MULTITOP, // Multiple top level modules
PINMISSING, // Cell pin not specified
PINNOCONNECT, // Cell pin not connected
PINCONNECTEMPTY,// Cell pin connected by name with empty reference
@ -131,7 +131,7 @@ public:
// Boolean
" I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
// Errors
"DETECTARRAY", "MULTITOP", "PORTSHORT", "TASKNSVAR",
"DETECTARRAY", "PORTSHORT", "TASKNSVAR",
// Warnings
" EC_FIRST_WARN",
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN",
@ -144,7 +144,7 @@ public:
"IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE",
"INCABSPATH", "INFINITELOOP", "INITIALDLY",
"LITENDIAN", "MODDUP",
"MULTIDRIVEN",
"MULTIDRIVEN", "MULTITOP",
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PROCASSWIRE",
"REALCVT", "REDEFMACRO",
"SELRANGE", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",

View File

@ -141,7 +141,8 @@ private:
// We'll throw the error when we know the module will really be needed.
string prettyName = AstNode::prettyName(modName);
V3Parse parser (v3Global.rootp(), m_filterp, m_parseSymp);
parser.parseFile(nodep->fileline(), prettyName, false, "");
// true below -> other simulators treat modules in link-found files as library cells
parser.parseFile(nodep->fileline(), prettyName, true, "");
V3Error::abortIfErrors();
// We've read new modules, grab new pointers to their names
readModNames();

View File

@ -674,18 +674,20 @@ class LinkDotFindVisitor : public AstNVisitor {
// packages before using packages
iterateChildrenBackwards(nodep);
// The first module in the list is always the top module (sorted before this is called).
// The first modules in the list are always the top modules
// (sorted before this is called).
// This may not be the module with isTop() set, as early in the steps,
// wrapTop may have not been created yet.
AstNodeModule* topmodp = nodep->modulesp();
if (!topmodp) {
if (!nodep->modulesp()) {
nodep->v3error("No top level module found");
} else {
UINFO(8,"Top Module: "<<topmodp<<endl);
}
for (AstNodeModule* modp = nodep->modulesp(); modp && modp->level() <= 2;
modp = VN_CAST(modp->nextp(), NodeModule)) {
UINFO(8,"Top Module: "<<modp<<endl);
m_scope = "TOP";
m_curSymp = m_modSymp = m_statep->insertTopCell(topmodp, m_scope);
m_curSymp = m_modSymp = m_statep->insertTopCell(modp, m_scope);
{
iterate(topmodp);
iterate(modp);
}
m_scope = "";
m_curSymp = m_modSymp = NULL;

View File

@ -60,17 +60,18 @@ void V3LinkLevel::modSortByLevel() {
if (nodep->level()<=2) {
if (topp) {
static int warnedOnce = 0;
nodep->v3warn(E_MULTITOP, "Unsupported: Multiple top level modules: "
<<nodep->prettyName()<<" and "<<topp->prettyName()<<endl
nodep->v3warn(MULTITOP, "Multiple top level modules: "
<<nodep->prettyName()<<" and "<<topp->prettyName()
<<(!warnedOnce++
? (nodep->warnMore()
+"... Fix, or use --top-module option to select which you want.")
? ("\n"+nodep->warnMore()
+"... Suggest see manual; fix the duplicates, or use --top-module to select top.")
: ""));
}
topp = nodep;
}
vec.push_back(nodep);
}
// Reorder the netlist's modules to have modules in level sorted order
stable_sort(vec.begin(), vec.end(), CmpLevel()); // Sort the vector
UINFO(9,"modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666
for (ModVec::iterator it = vec.begin(); it != vec.end(); ++it) {
@ -95,7 +96,10 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) {
UINFO(2,__FUNCTION__<<": "<<endl);
// We do ONLY the top module
AstNodeModule* oldmodp = rootp->modulesp();
if (!oldmodp) rootp->v3fatalSrc("No module found to process");
if (!oldmodp) { // Later V3LinkDot will warn
UINFO(1,"No module found to wrap\n");
return;
}
AstNodeModule* newmodp = new AstModule(oldmodp->fileline(), string("TOP"));
// Make the new module first in the list
oldmodp->unlinkFrBackWithNext();
@ -108,62 +112,10 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) {
// the rest must be done after data type resolution
wrapTopCell(rootp);
V3Global::dumpCheckGlobalTree("wraptop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}
void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
AstNodeModule* newmodp = rootp->modulesp();
if (!newmodp || !newmodp->isTop()) rootp->v3fatalSrc("No TOP module found to process");
AstNodeModule* oldmodp = VN_CAST(newmodp->nextp(), NodeModule);
if (!oldmodp) rootp->v3fatalSrc("No module found to process");
// Add instance
AstCell* cellp = new AstCell(newmodp->fileline(),
(!v3Global.opt.l2Name().empty()
? v3Global.opt.l2Name() : oldmodp->name()),
oldmodp->name(),
NULL, NULL, NULL);
cellp->modp(oldmodp);
newmodp->addStmtp(cellp);
// Add pins
for (AstNode* subnodep=oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
if (AstVar* oldvarp = VN_CAST(subnodep, Var)) {
UINFO(8,"VARWRAP "<<oldvarp<<endl);
if (oldvarp->isIO()) {
AstVar* varp = oldvarp->cloneTree(false);
newmodp->addStmtp(varp);
varp->sigPublic(true); // User needs to be able to get to it...
if (oldvarp->isIO()) {
oldvarp->primaryIO(false);
varp->primaryIO(true);
}
if (varp->direction().isRefOrConstRef()) {
varp->v3error("Unsupported: ref/const ref as primary input/output: "
<<varp->prettyName());
}
if (varp->isIO() && v3Global.opt.systemC()) {
varp->sc(true);
// User can see trace one level down from the wrapper
// Avoids packing & unpacking SC signals a second time
varp->trace(false);
}
AstPin* pinp = new AstPin(oldvarp->fileline(), 0, oldvarp->name(),
new AstVarRef(varp->fileline(),
varp, oldvarp->isWritable()));
// Skip length and width comp; we know it's a direct assignment
pinp->modVarp(oldvarp);
cellp->addPinsp(pinp);
}
}
}
// Instantiate all packages under the top wrapper
// This way all later SCOPE based optimizations can ignore packages
for (AstNodeModule* modp = rootp->modulesp(); modp; modp=VN_CAST(modp->nextp(), NodeModule)) {
if (VN_IS(modp, Package)
&& modp != oldmodp) { // Don't duplicate if didn't find a top module
if (VN_IS(modp, Package)) {
AstCell* cellp = new AstCell(modp->fileline(),
// Could add __03a__03a="::" to prevent conflict
// with module names/"v"
@ -174,4 +126,89 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
newmodp->addStmtp(cellp);
}
}
V3Global::dumpCheckGlobalTree("wraptop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}
void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
AstNodeModule* newmodp = rootp->modulesp();
if (!newmodp || !newmodp->isTop()) rootp->v3fatalSrc("No TOP module found to insert under");
// Find all duplicate signal names (if multitop)
typedef vl_unordered_set<std::string> NameSet;
NameSet ioNames;
NameSet dupNames;
// For all modulues, skipping over new top
for (AstNodeModule* oldmodp = VN_CAST(rootp->modulesp()->nextp(), NodeModule);
oldmodp && oldmodp->level() <= 2;
oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
if (AstVar* oldvarp = VN_CAST(subnodep, Var)) {
if (oldvarp->isIO()) {
if (ioNames.find(oldvarp->name()) != ioNames.end()) {
//UINFO(8, "Multitop dup I/O found: "<<oldvarp<<endl);
dupNames.insert(oldvarp->name());
} else {
ioNames.insert(oldvarp->name());
}
}
}
}
}
// For all modulues, skipping over new top
for (AstNodeModule* oldmodp = VN_CAST(rootp->modulesp()->nextp(), NodeModule);
oldmodp && oldmodp->level() <= 2;
oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
if (VN_IS(oldmodp, Package)) continue;
// Add instance
UINFO(5,"LOOP "<<oldmodp<<endl);
AstCell* cellp = new AstCell(newmodp->fileline(),
(!v3Global.opt.l2Name().empty()
? v3Global.opt.l2Name() : oldmodp->name()),
oldmodp->name(),
NULL, NULL, NULL);
cellp->modp(oldmodp);
newmodp->addStmtp(cellp);
// Add pins
for (AstNode* subnodep=oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
if (AstVar* oldvarp = VN_CAST(subnodep, Var)) {
UINFO(8,"VARWRAP "<<oldvarp<<endl);
if (oldvarp->isIO()) {
string name = oldvarp->name();
if (dupNames.find(name) != dupNames.end()) {
// __02E=. while __DOT__ looks nicer but will break V3LinkDot
name = oldmodp->name()+"__02E"+name;
}
AstVar* varp = oldvarp->cloneTree(false);
varp->name(name);
newmodp->addStmtp(varp);
varp->sigPublic(true); // User needs to be able to get to it...
if (oldvarp->isIO()) {
oldvarp->primaryIO(false);
varp->primaryIO(true);
}
if (varp->direction().isRefOrConstRef()) {
varp->v3error("Unsupported: ref/const ref as primary input/output: "
<<varp->prettyName());
}
if (varp->isIO() && v3Global.opt.systemC()) {
varp->sc(true);
// User can see trace one level down from the wrapper
// Avoids packing & unpacking SC signals a second time
varp->trace(false);
}
AstPin* pinp = new AstPin(oldvarp->fileline(), 0, varp->name(),
new AstVarRef(varp->fileline(),
varp, oldvarp->isWritable()));
// Skip length and width comp; we know it's a direct assignment
pinp->modVarp(oldvarp);
cellp->addPinsp(pinp);
}
}
}
}
}

View File

@ -90,7 +90,7 @@ private:
// VISITORS
virtual void visit(AstNetlist* nodep) {
AstNodeModule* modp = nodep->topModulep();
if (!modp) { nodep->v3error("No root module specified"); return; }
if (!modp) { nodep->v3error("No top level module found"); return; }
// Operate starting at the top of the hierarchy
m_aboveCellp = NULL;
m_aboveScopep = NULL;

View File

@ -1,4 +1,5 @@
%Error-MULTITOP: t/t_flag_topmodule.v:14: Unsupported: Multiple top level modules: a2 and a
t/t_flag_topmodule.v:14: ... Fix, or use --top-module option to select which you want.
%Error-MULTITOP: t/t_flag_topmodule.v:21: Unsupported: Multiple top level modules: b and a2
%Warning-MULTITOP: t/t_flag_topmodule.v:14: Multiple top level modules: a2 and a
t/t_flag_topmodule.v:14: ... Suggest see manual; fix the duplicates, or use --top-module to select top.
... Use "/* verilator lint_off MULTITOP */" and lint_on around source to disable this message.
%Warning-MULTITOP: t/t_flag_topmodule.v:21: Multiple top level modules: b and a2
%Error: Exiting due to

View File

@ -1,6 +1,6 @@
%Warning-MODDUP: t/t_mod_dup_bad.v:13: Duplicate declaration of module: a
t/t_mod_dup_bad.v:6: ... Location of original declaration
... Use "/* verilator lint_off MODDUP */" and lint_on around source to disable this message.
%Error-MULTITOP: t/t_mod_dup_bad.v:16: Unsupported: Multiple top level modules: b and test
t/t_mod_dup_bad.v:16: ... Fix, or use --top-module option to select which you want.
%Warning-MULTITOP: t/t_mod_dup_bad.v:16: Multiple top level modules: b and test
t/t_mod_dup_bad.v:16: ... Suggest see manual; fix the duplicates, or use --top-module to select top.
%Error: Exiting due to

25
test_regress/t/t_multitop1.pl Executable file
View File

@ -0,0 +1,25 @@
#!/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.
scenarios(vlt_all => 1);
compile(
);
execute(
check_finished => 0,
);
# Order of lines is unspecified, so don't use a golden file
file_grep($Self->{run_log_filename}, qr!In 'top.t'!);
file_grep($Self->{run_log_filename}, qr!In 'top.t.s'!);
file_grep_not($Self->{run_log_filename}, qr!in_subfile!);
ok(1);
1;

View File

@ -0,0 +1,17 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2019 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
t_multitop1s s ();
initial $display("In '%m'");
always @(posedge clk) begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,12 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2019 by Wilson Snyder.
module t_multitop1s;
initial $display("In '%m'");
endmodule
module in_subfile;
initial $display("In '%m'");
endmodule

View File

@ -0,0 +1,44 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
#include <iostream>
#include <verilated.h>
#include "Vt_multitop_sig.h"
// Use cout to avoid issues with %d/%lx etc
#define CHECK_RESULT(got, exp) \
if ((got) != (exp)) { \
std::cout<<std::dec<<"%Error: "<<__FILE__<<":"<<__LINE__ \
<<": GOT = "<<(got)<<" EXP = "<<(exp)<<std::endl; \
return __LINE__; \
}
int main(int argc, char *argv[]) {
Vt_multitop_sig *topp = new Vt_multitop_sig("");
Verilated::debug(0);
{
topp->a__02Ein = 0;
topp->b__02Ein = 0;
topp->uniq_in = 0;
topp->eval();
CHECK_RESULT(topp->a__02Eout, 1);
CHECK_RESULT(topp->b__02Eout, 0);
CHECK_RESULT(topp->uniq_out, 1);
topp->a__02Ein = 1;
topp->b__02Ein = 1;
topp->uniq_in = 1;
topp->eval();
CHECK_RESULT(topp->a__02Eout, 0);
CHECK_RESULT(topp->b__02Eout, 1);
CHECK_RESULT(topp->uniq_out, 0);
}
printf("*-* All Finished *-*\n");
}

View File

@ -0,0 +1,30 @@
#!/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.
scenarios(vlt_all => 1);
compile(
make_top_shell => 0,
make_main => 0,
verilator_flags2 => ["-Wno-MULTITOP --exe $Self->{t_dir}/$Self->{name}.cpp"],
);
execute(
check_finished => 1,
);
file_grep($Self->{run_log_filename}, qr!In 'a'!);
file_grep($Self->{run_log_filename}, qr!In 'a.sub'!);
file_grep($Self->{run_log_filename}, qr!In 'b'!);
file_grep($Self->{run_log_filename}, qr!In 'b.sub'!);
file_grep($Self->{run_log_filename}, qr!In 'c'!);
file_grep($Self->{run_log_filename}, qr!In 'c.sub'!);
ok(1);
1;

View File

@ -0,0 +1,32 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2019 by Wilson Snyder.
module a(in, out);
input in;
output out;
assign out = !in;
sub sub ();
initial $display("In '%m'");
endmodule
module b(in, out);
input in;
output out;
assign out = in;
sub sub ();
initial $display("In '%m'");
endmodule
module c(uniq_in, uniq_out);
input uniq_in;
output uniq_out;
assign uniq_out = !uniq_in;
sub sub ();
initial $display("In '%m'");
endmodule
module sub;
initial $display("In '%m'");
endmodule

View File

@ -0,0 +1,5 @@
%Warning-MULTITOP: t/t_multitop_sig.v:14: Multiple top level modules: b and a
t/t_multitop_sig.v:14: ... Suggest see manual; fix the duplicates, or use --top-module to select top.
... Use "/* verilator lint_off MULTITOP */" and lint_on around source to disable this message.
%Warning-MULTITOP: t/t_multitop_sig.v:22: Multiple top level modules: c and b
%Error: Exiting due to

View File

@ -0,0 +1,20 @@
#!/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.
scenarios(simulator => 1);
top_filename("t/t_multitop_sig.v");
compile(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;