diff --git a/Changes b/Changes index ab0807c71..518265821 100644 --- a/Changes +++ b/Changes @@ -19,6 +19,7 @@ Verilator 5.011 devel **Minor:** * Support get_randstate/set_randstate class method function. +* Add creating __inputs.vpp file with --debug (#4177). [Tudor Timi] * Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk] * Fix crash on duplicate imported modules (#3231). [Robert Balas] * Fix false WIDTHEXPAND on array declarations (#3959). [JOTEGO] diff --git a/docs/guide/files.rst b/docs/guide/files.rst index d34ea6aa7..219979350 100644 --- a/docs/guide/files.rst +++ b/docs/guide/files.rst @@ -126,8 +126,10 @@ In specific debug and other modes, it also creates: - Debugging graph files (from --debug) * - *{prefix}{misc}*\ .tree - Debugging files (from --debug) - * - {mod_prefix}_{each_verilog_base_filename}*\ .vpp - - Pre-processed verilog (from --debug) + * - *{prefix}*\ __inputs\ .vpp + - Pre-processed verilog for all files (from --debug) + * - *{prefix}*\ _ *{each_verilog_base_filename}*\ .vpp + - Pre-processed verilog for each file (from --debug) After running Make, the C++ compiler may produce the following: diff --git a/docs/internals.rst b/docs/internals.rst index c055aae8c..ecd9dc5f2 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -1503,8 +1503,19 @@ debug level 5, with the V3Width.cpp file at level 9. --debug ------- -When you run with ``--debug``, there are two primary output file types -placed into the obj_dir, .tree and .dot files. +When you run with ``--debug``, there are three primary output file types +placed into the obj_dir, .vpp, .tree and .dot files. + +.vpp Output +----------- + +Verilator creates a *{mod_prefix}*\ __inputs\ .vpp file containing all the +files that were read, filtered by preprocessing. This file can be fed back +into Verilator, replacing on the command line all of the previous input +files, to enable simplification of test cases. + +Verilator also creates .vpp files for each individual file passed on the +command line. .dot Output diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index cbf1808d5..c7e2e62b4 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -35,6 +35,7 @@ #include "V3Os.h" #include "V3ParseBison.h" // Generated by bison #include "V3PreShell.h" +#include "V3Stats.h" #include @@ -247,24 +248,22 @@ size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) { return got; } -void V3ParseImp::preprocDumps(std::ostream& os) { - if (v3Global.opt.dumpDefines()) { - V3PreShell::dumpDefines(os); - } else { - const bool noblanks = v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine(); - for (auto& buf : m_ppBuffers) { - if (noblanks) { - bool blank = true; - for (string::iterator its = buf.begin(); its != buf.end(); ++its) { - if (!std::isspace(*its) && *its != '\n') { - blank = false; - break; - } +void V3ParseImp::preprocDumps(std::ostream& os, bool forInputs) { + bool noblanks = forInputs || (v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine()); + bool nolines = forInputs; + for (auto& buf : m_ppBuffers) { + if (noblanks) { + bool blank = true; + for (string::iterator its = buf.begin(); its != buf.end(); ++its) { + if (!std::isspace(*its) && *its != '\n') { + blank = false; + break; } - if (blank) continue; } - os << buf; + if (blank) continue; + if (nolines && buf.rfind("`line ", 0) == 0) continue; } + os << buf; } } @@ -292,7 +291,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i if (v3Global.opt.preprocOnly() || v3Global.opt.keepTempFiles()) { // Create output file with all the preprocessor output we buffered up const string vppfilename = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix() - + "_" + nondirname + ".vpp"; + + "__" + nondirname + ".vpp"; std::ofstream* ofp = nullptr; std::ostream* osp; if (v3Global.opt.preprocOnly()) { @@ -303,15 +302,20 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i if (osp->fail()) { fileline->v3error("Cannot write preprocessor output: " + vppfilename); return; + } + if (v3Global.opt.dumpDefines()) { + V3PreShell::dumpDefines(*osp); } else { - preprocDumps(*osp); - if (ofp) { - ofp->close(); - VL_DO_DANGLING(delete ofp, ofp); - } + preprocDumps(*osp, false); + } + if (ofp) { + ofp->close(); + VL_DO_DANGLING(delete ofp, ofp); } } + if (debug() && modfilename != V3Options::getStdPackagePath()) dumpInputsFile(); + // Parse it if (!v3Global.opt.preprocOnly()) { lexFile(modfilename); @@ -320,6 +324,31 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i } } +void V3ParseImp::dumpInputsFile() { + // Create output file with joined preprocessor output we buffered up, + // Useful for debug to feed back into Verilator + static bool append = false; + const string vppfilename + = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix() + "__inputs.vpp"; + std::ofstream* ofp = V3File::new_ofstream(vppfilename, append); + if (ofp->fail()) { + v3error("Cannot write preprocessor output: " + vppfilename); + return; + } + if (!append) { + append = true; + UINFO(1, "Writing all preprocessed output to " << vppfilename << endl); + *ofp << "// Dump of all post-preprocessor input\n"; + *ofp << "// Blank lines and `line directives have been removed\n"; + *ofp << "//\n"; + V3Stats::infoHeader(*ofp, "// "); + } + *ofp << "\n"; + preprocDumps(*ofp, true); + ofp->close(); + VL_DO_DANGLING(delete ofp, ofp); +} + void V3ParseImp::lexFile(const string& modname) { // Prepare for lexing UINFO(3, "Lexing " << modname << endl); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index e1037b130..bba341102 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -295,6 +295,7 @@ public: void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary, const string& errmsg); + void dumpInputsFile(); private: void lexFile(const string& modname); @@ -305,7 +306,7 @@ private: size_t tokenPipeScanParam(size_t depth); size_t tokenPipeScanType(size_t depth); const V3ParseBisonYYSType* tokenPeekp(size_t depth); - void preprocDumps(std::ostream& os); + void preprocDumps(std::ostream& os, bool forInputs); }; #endif // Guard diff --git a/src/V3Stats.h b/src/V3Stats.h index fb56fbfe8..97c61050b 100644 --- a/src/V3Stats.h +++ b/src/V3Stats.h @@ -121,6 +121,8 @@ public: static void statsFinalAll(AstNetlist* nodep); /// Called by the top level to dump the statistics static void statsReport(); + /// Called by debug dumps + static void infoHeader(std::ofstream& os, const string& prefix); }; #endif // Guard diff --git a/src/V3StatsReport.cpp b/src/V3StatsReport.cpp index d72f13c1c..c725a40f5 100644 --- a/src/V3StatsReport.cpp +++ b/src/V3StatsReport.cpp @@ -40,18 +40,8 @@ class StatsReport final { std::ofstream& os; ///< Output stream static StatColl s_allStats; ///< All statistics - void header() { - os << "Verilator Statistics Report\n\n"; - - os << "Information:\n"; - os << " " << V3Options::version() << '\n'; - os << " Arguments: " << v3Global.opt.allArgsString() << '\n'; - os << " Build jobs: " << v3Global.opt.buildJobs() << '\n'; - os << " Verilate jobs: " << v3Global.opt.verilateJobs() << '\n'; - os << '\n'; - } - void sumit() { + os << '\n'; // If sumit is set on a statistic, combine with others of same name std::multimap byName; // * is always first @@ -179,7 +169,8 @@ public: // CONSTRUCTORS explicit StatsReport(std::ofstream* aofp) : os(*aofp) { // Need () or GCC 4.8 false warning - header(); + os << "Verilator Statistics Report\n\n"; + V3Stats::infoHeader(os, ""); sumit(); stars(); stages(); @@ -222,6 +213,14 @@ void V3Stats::statsStage(const string& name) { V3Stats::addStatPerf("Stage, Memory (MB), " + digitName, memory); } +void V3Stats::infoHeader(std::ofstream& os, const string& prefix) { + os << prefix << "Information:\n"; + os << prefix << " " << V3Options::version() << '\n'; + os << prefix << " Arguments: " << v3Global.opt.allArgsString() << '\n'; + os << prefix << " Build jobs: " << v3Global.opt.buildJobs() << '\n'; + os << prefix << " Verilate jobs: " << v3Global.opt.verilateJobs() << '\n'; +} + void V3Stats::statsReport() { UINFO(2, __FUNCTION__ << ": " << endl); diff --git a/test_regress/t/t_debug_inputs.pl b/test_regress/t/t_debug_inputs.pl new file mode 100755 index 000000000..9b9054d09 --- /dev/null +++ b/test_regress/t/t_debug_inputs.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + v_flags => ["--debug --debugi 1 -Wno-MULTITOP t/t_debug_inputs_b.v"], + ); + +file_grep("$Self->{obj_dir}/V$Self->{name}__inputs.vpp", qr/module t_debug_inputs /); +file_grep("$Self->{obj_dir}/V$Self->{name}__inputs.vpp", qr/module t_debug_inputs_a /); +file_grep("$Self->{obj_dir}/V$Self->{name}__inputs.vpp", qr/module t_debug_inputs_b /); + +ok(1); +1; diff --git a/test_regress/t/t_debug_inputs.v b/test_regress/t/t_debug_inputs.v new file mode 100644 index 000000000..0e4f4c44d --- /dev/null +++ b/test_regress/t/t_debug_inputs.v @@ -0,0 +1,11 @@ +// DESCRIPTION: Verilator: Dotted reference that uses another dotted reference +// as the select expression +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`include "t/t_debug_inputs_a.v" + +module t_debug_inputs (/*AUTOARG*/); +endmodule diff --git a/test_regress/t/t_debug_inputs_a.v b/test_regress/t/t_debug_inputs_a.v new file mode 100644 index 000000000..7754ce73a --- /dev/null +++ b/test_regress/t/t_debug_inputs_a.v @@ -0,0 +1,9 @@ +// DESCRIPTION: Verilator: Dotted reference that uses another dotted reference +// as the select expression +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t_debug_inputs_a (/*AUTOARG*/); +endmodule diff --git a/test_regress/t/t_debug_inputs_b.v b/test_regress/t/t_debug_inputs_b.v new file mode 100644 index 000000000..7321188ab --- /dev/null +++ b/test_regress/t/t_debug_inputs_b.v @@ -0,0 +1,9 @@ +// DESCRIPTION: Verilator: Dotted reference that uses another dotted reference +// as the select expression +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t_debug_inputs_b (/*AUTOARG*/); +endmodule