diff --git a/Changes b/Changes index 9945d0d94..22aa14cc3 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Add sc_bv attribute to force bit vectors, bug402. [by Stefan Wallentowitz] +**** Fix reporting not found modules if generate-off, bug403. [Jeremy Bennett] + * Verilator 3.824 2011/10/25 diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 969d5c1e3..c7c0faeae 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -973,6 +973,14 @@ struct AstModule : public AstNodeModule { virtual string verilogKwd() const { return "module"; } }; +struct AstNotFoundModule : public AstNodeModule { + // A missing module declaration + AstNotFoundModule(FileLine* fl, const string& name) + : AstNodeModule (fl,name) {} + ASTNODE_NODE_FUNCS(NotFoundModule, NOTFOUNDMODULE) + virtual string verilogKwd() const { return "/*not-found-*/ module"; } +}; + struct AstPackage : public AstNodeModule { // A package declaration AstPackage(FileLine* fl, const string& name) diff --git a/src/V3Link.cpp b/src/V3Link.cpp index 1aad1e5ef..f273b7b1c 100644 --- a/src/V3Link.cpp +++ b/src/V3Link.cpp @@ -563,8 +563,13 @@ private: nodep->v3fatalSrc("Cell has unlinked module"); // V3LinkCell should have errored out } else { + if (nodep->modp()->castNotFoundModule()) { + // Prevent warnings about missing pin connects + if (nodep->pinsp()) nodep->pinsp()->unlinkFrBackWithNext()->deleteTree(); + if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree(); + } // Need to pass the module info to this cell, so we can link up the pin names - if (m_idState==ID_RESOLVE) { + else if (m_idState==ID_RESOLVE) { m_cellVarsp = nodep->modp()->user4p()->castSymTable(); UINFO(4,"(Backto) Link Cell: "<dumpTree(cout,"linkcell:"); } diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index edbe0d55d..6b1b72617 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -176,8 +176,10 @@ private: AstNodeModule* modp = m_mods.findIdUpward(nodep->modName())->castNodeModule(); if (!modp) { // Read-subfile + // If file not found, make AstNotFoundModule, rather than error out. + // We'll throw the error when we know the module will really be needed. V3Parse parser (v3Global.rootp(), m_filterp); - parser.parseFile(nodep->fileline(), nodep->modName(), false); + parser.parseFile(nodep->fileline(), nodep->modName(), false, ""); V3Error::abortIfErrors(); // We've read new modules, grab new pointers to their names readModNames(); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index ea134b9a9..9e4824885 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -288,7 +288,8 @@ string V3Options::fileExists (const string& filename) { return filenameOut; } -string V3Options::filePath (FileLine* fl, const string& modname, const string& errmsg) { +string V3Options::filePath (FileLine* fl, const string& modname, + const string& errmsg) { // Error prefix or "" to suppress error // Find a filename to read the specified module name, // using the incdir and libext's. // Return "" if not found. @@ -305,7 +306,14 @@ string V3Options::filePath (FileLine* fl, const string& modname, const string& e } // Warn and return not found - fl->v3error(errmsg+modname); + if (errmsg != "") { + fl->v3error(errmsg+modname); + filePathLookedMsg(fl, modname); + } + return ""; +} + +void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) { static bool shown_notfound_msg = false; if (!shown_notfound_msg) { shown_notfound_msg = true; @@ -321,7 +329,6 @@ string V3Options::filePath (FileLine* fl, const string& modname, const string& e } } } - return ""; } void V3Options::unlinkRegexp(const string& dir, const string& regexp) { diff --git a/src/V3Options.h b/src/V3Options.h index 21bc065e7..3a466fcc2 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -345,6 +345,7 @@ class V3Options { // METHODS (file utilities using these options) string fileExists (const string& filename); string filePath (FileLine* fl, const string& modname, const string& errmsg); + void filePathLookedMsg(FileLine* fl, const string& modname); static bool fileStatDir (const string& filename); static bool fileStatNormal (const string& filename); diff --git a/src/V3Parse.h b/src/V3Parse.h index 1c9c74c7c..24724a86b 100644 --- a/src/V3Parse.h +++ b/src/V3Parse.h @@ -45,7 +45,8 @@ public: // METHODS // Preprocess and read the Verilog file specified into the netlist database - void parseFile(FileLine* fileline, const string& modname, bool inLibrary); + void parseFile(FileLine* fileline, const string& modname, bool inLibrary, + const string& errmsg); // Push preprocessed text to the lexer static void ppPushText(V3ParseImp* impp, const string& text); diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index 8b1412f4d..202031c55 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -89,7 +89,8 @@ size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) { return got; } -void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool inLibrary) { +void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool inLibrary, + const string& errmsg) { // "" for no error, make fake node string modname = V3Options::filenameNonExt(modfilename); UINFO(2,__FUNCTION__<<": "<addModulep(nodep); + return; + } if (v3Global.opt.preprocOnly() || v3Global.opt.keepTempFiles()) { // Create output file with all the preprocessor output we buffered up @@ -157,8 +165,9 @@ V3Parse::V3Parse(AstNetlist* rootp, V3InFilter* filterp) { V3Parse::~V3Parse() { delete m_impp; m_impp = NULL; } -void V3Parse::parseFile(FileLine* fileline, const string& modname, bool inLibrary) { - m_impp->parseFile(fileline, modname, inLibrary); +void V3Parse::parseFile(FileLine* fileline, const string& modname, bool inLibrary, + const string& errmsg) { + m_impp->parseFile(fileline, modname, inLibrary, errmsg); } void V3Parse::ppPushText(V3ParseImp* impp, const string& text) { impp->ppPushText(text); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 3d5e8b0e9..4c7b7b6a8 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -333,7 +333,8 @@ public: // Preprocess and read the Verilog file specified into the netlist database int lexToBison(); // Pass token to bison - void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary); + void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary, + const string& errmsg); private: void lexFile(const string& modname); diff --git a/src/V3PreShell.cpp b/src/V3PreShell.cpp index b1a89b897..b3a1a4eea 100644 --- a/src/V3PreShell.cpp +++ b/src/V3PreShell.cpp @@ -74,7 +74,8 @@ protected: } } - void preproc (FileLine* fl, const string& modname, V3InFilter* filterp, V3ParseImp* parsep) { + bool preproc (FileLine* fl, const string& modname, V3InFilter* filterp, V3ParseImp* parsep, + const string& errmsg) { // "" for no error debug(true); // Recheck if debug on - first check was before command line passed // Preprocess the given module, putting output in vppFilename @@ -82,11 +83,14 @@ protected: // Preprocess s_filterp = filterp; - preprocOpen(fl, s_filterp, modname, "Cannot find file containing module: "); + bool ok = preprocOpen(fl, s_filterp, modname, errmsg); + if (!ok) return false; + while (!s_preprocp->isEof()) { string line = s_preprocp->getline(); V3Parse::ppPushText(parsep, line); } + return true; } void preprocInclude (FileLine* fl, const string& modname) { @@ -96,17 +100,20 @@ protected: preprocOpen(fl, s_filterp, modname, "Cannot find include file: "); } - void preprocOpen (FileLine* fl, V3InFilter* filterp, const string& modname, const string& errmsg) { + bool preprocOpen (FileLine* fl, V3InFilter* filterp, const string& modname, + const string& errmsg) { // Error message or "" to suppress + // Returns true if successful // Allow user to put `defined names on the command line instead of filenames, // then convert them properly. string ppmodname = s_preprocp->removeDefines (modname); // Open include or master file string filename = v3Global.opt.filePath (fl, ppmodname, errmsg); - if (filename=="") return; // Not found + if (filename=="") return false; // Not found UINFO(2," Reading "<openFile(fl, filterp, filename); + return true; } // CONSTRUCTORS @@ -124,8 +131,9 @@ V3InFilter* V3PreShellImp::s_filterp = NULL; void V3PreShell::boot(char** env) { V3PreShellImp::s_preImp.boot(env); } -void V3PreShell::preproc(FileLine* fl, const string& modname, V3InFilter* filterp, V3ParseImp* parsep) { - V3PreShellImp::s_preImp.preproc(fl, modname, filterp, parsep); +bool V3PreShell::preproc(FileLine* fl, const string& modname, V3InFilter* filterp, + V3ParseImp* parsep, const string& errmsg) { + return V3PreShellImp::s_preImp.preproc(fl, modname, filterp, parsep, errmsg); } void V3PreShell::preprocInclude(FileLine* fl, const string& modname) { V3PreShellImp::s_preImp.preprocInclude(fl, modname); diff --git a/src/V3PreShell.h b/src/V3PreShell.h index 51747916b..8a7052b40 100644 --- a/src/V3PreShell.h +++ b/src/V3PreShell.h @@ -36,7 +36,8 @@ class V3PreShell { // Static class for calling preprocessor public: static void boot(char** env); - static void preproc(FileLine* fileline, const string& module, V3InFilter* filterp, V3ParseImp* parsep); + static bool preproc(FileLine* fileline, const string& module, V3InFilter* filterp, + V3ParseImp* parsep, const string& errmsg); static void preprocInclude(FileLine* fileline, const string& module); static string dependFiles() { return ""; } // Perl only static void defineCmdLine(const string& name, const string& value); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 8371d2051..e3b334b1d 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1137,6 +1137,13 @@ private: } virtual void visit(AstCell* nodep, AstNUser*) { if (!m_paramsOnly) { + if (nodep->modp()->castNotFoundModule()) { + // We've resolved parameters and hit a module that we couldn't resolve. It's + // finally time to report it. + // Note only here in V3Width as this is first visitor after V3Dead. + nodep->v3error("Cannot find file containing module: "<modName()); + v3Global.opt.filePathLookedMsg(nodep->fileline(), nodep->modName()); + } if (nodep->rangep()) { m_cellRangep = nodep->rangep(); nodep->rangep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 40480387d..13ab8bdaa 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -106,7 +106,8 @@ void V3Global::readFiles() { for (V3StringList::const_iterator it = v3Global.opt.vFiles().begin(); it != v3Global.opt.vFiles().end(); ++it) { string filename = *it; - parser.parseFile(new FileLine("COMMAND_LINE",0), filename, false); + parser.parseFile(new FileLine("COMMAND_LINE",0), filename, false, + "Cannot find file containing module: "); } // Read libraries @@ -115,7 +116,8 @@ void V3Global::readFiles() { for (V3StringSet::const_iterator it = v3Global.opt.libraryFiles().begin(); it != v3Global.opt.libraryFiles().end(); ++it) { string filename = *it; - parser.parseFile(new FileLine("COMMAND_LINE",0), filename, true); + parser.parseFile(new FileLine("COMMAND_LINE",0), filename, true, + "Cannot find file containing library module: "); } //v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("parse.tree")); V3Error::abortIfErrors(); diff --git a/test_regress/t/t_gen_missing.pl b/test_regress/t/t_gen_missing.pl new file mode 100755 index 000000000..bfdf34e07 --- /dev/null +++ b/test_regress/t/t_gen_missing.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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 => ['+define+T_GEN_MISSING'], + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_gen_missing.v b/test_regress/t/t_gen_missing.v new file mode 100644 index 000000000..f922da616 --- /dev/null +++ b/test_regress/t/t_gen_missing.v @@ -0,0 +1,58 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2011 by Wilson Snyder. + +module t; +`ifdef T_GEN_MISSING_BAD + foobar #(.FOO_TYPE(1)) foobar; // This means we should instatiate missing module +`elsif T_GEN_MISSING + foobar #(.FOO_TYPE(0)) foobar; // This means we should instatiate foo0 +`else + `error "Bad Test" +`endif +endmodule + + +module foobar + #( parameter + FOO_START = 0, + FOO_NUM = 2, + FOO_TYPE = 1 + ) + ( + input wire[FOO_NUM-1:0] foo, + output wire[FOO_NUM-1:0] bar); + + + generate + begin: g + genvar j; + for (j = FOO_START; j < FOO_NUM+FOO_START; j = j + 1) + begin: foo_inst; + if (FOO_TYPE == 0) + begin: foo_0 + // instatiate foo0 + foo0 i_foo(.x(foo[j]), .y(bar[j])); + end + if (FOO_TYPE == 1) + begin: foo_1 + // instatiate foo1 + foo_not_needed i_foo(.x(foo[j]), .y(bar[j])); + end + end + end + endgenerate +endmodule + + + +module foo0(input wire x, output wire y); + + assign y = ~x; + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_gen_missing_bad.pl b/test_regress/t/t_gen_missing_bad.pl new file mode 100755 index 000000000..491c56046 --- /dev/null +++ b/test_regress/t/t_gen_missing_bad.pl @@ -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 2003 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. + +top_filename("t/t_gen_missing.v"); + +$Self->{vlt} or $Self->skip("Verilator only test"); +compile ( + v_flags2 => ['+define+T_GEN_MISSING_BAD'], + fails => 1, + expect=> +'%Error: t/t_gen_missing.v:\d+: Cannot find file containing module: foo_not_needed +%Error: t/t_gen_missing.v:\d+: Looked in: +%Error: t/t_gen_missing.v:\d+: foo_not_needed +%Error: t/t_gen_missing.v:\d+: foo_not_needed.v +%Error: t/t_gen_missing.v:\d+: foo_not_needed.sv +.*%Error: Exiting due to.*', + ); + +ok(1); +1;