From 482bdab0e0abdf9724e0558c99f6c242eea24381 Mon Sep 17 00:00:00 2001 From: Stefan Wallentowitz Date: Thu, 24 Mar 2016 19:14:15 -0400 Subject: [PATCH] Support command-line -G/+pvalue param overrides, bug1045. Signed-off-by: Wilson Snyder --- Changes | 2 ++ bin/verilator | 55 +++++++++++++++++++++++++++--- src/V3LinkDot.cpp | 55 ++++++++++++++++++++++++++++++ src/V3Options.cpp | 50 +++++++++++++++++++++++++++ src/V3Options.h | 7 ++++ src/Verilator.cpp | 2 ++ test_regress/t/t_flag_parameter.pl | 20 +++++++++++ test_regress/t/t_flag_parameter.v | 49 ++++++++++++++++++++++++++ test_regress/t/t_flag_parameter.vc | 15 ++++++++ 9 files changed, 251 insertions(+), 4 deletions(-) create mode 100755 test_regress/t/t_flag_parameter.pl create mode 100644 test_regress/t/t_flag_parameter.v create mode 100644 test_regress/t/t_flag_parameter.vc diff --git a/Changes b/Changes index b6c01536c..35ece85a1 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,8 @@ indicates the contributor was also the author of the fix; Thanks! ** Support parameter type, bug376. [Alan Hunter, et al] +** Support command-line -G/+pvalue param overrides, bug1045. [Stefan Wallentowitz] + * Verilator 3.882 2016-03-01 diff --git a/bin/verilator b/bin/verilator index a6cd39c73..f7f0e2c25 100755 --- a/bin/verilator +++ b/bin/verilator @@ -54,7 +54,18 @@ push @ARGV, (split ' ',$ENV{VERILATOR_TEST_FLAGS}||""); # We sneak a look at the flags so we can do some pre-environment checks # All flags will hit verilator... foreach my $sw (@ARGV) { - $sw = "'$sw'" if $sw =~ m![^---a-zA-Z0-9_/\\:.+]!; + # Some special treatment for parameters to allow verilog literals for numbers + if ((substr($sw, 0, 2) eq "-G") || (substr($sw, 0, 8) eq "-pvalue+")) { + # If there is a single quote in the parameter put it double quotes , + # else just put it in double quotes + if ($sw =~ m![\']!) { + $sw = "\"$sw\""; + } else { + $sw = "'$sw'"; + } + } else { + $sw = "'$sw'" if $sw =~ m![^---a-zA-Z0-9_/\\:.+]!; + } push @Opt_Verilator_Sw, $sw; } @@ -269,6 +280,7 @@ descriptions in the next sections for more information. --exe Link to create executable -F Parse options from a file, relatively -f Parse options from a file + -G= Overwrite toplevel parameter --gdb Run Verilator under GDB interactively --gdbbt Run Verilator under GDB for backtrace --help Display this help @@ -308,6 +320,7 @@ descriptions in the next sections for more information. --profile-cfuncs Name functions for profiling --private Debugging; see docs --public Debugging; see docs + -pvalue+= Overwrite toplevel parameter --report-unoptflat Extra diagnostics for UNOPTFLAT --savable Enable model save-restore --sc Create SystemC output @@ -688,6 +701,35 @@ The file may contain // comments which are ignored to the end of the line. Any $VAR, $(VAR), or ${VAR} will be replaced with the specified environment variable. +=item -GI=I + +Overwrites the given parameter of the toplevel module. The value is limited +to basic data literals: + +=over 4 + +=item Verilog integer literals + +The standard verilog integer literals are supported, so values like 32'h8, +2'b00, 4 etc. are allowed. Care must be taken that the single quote (I') is +properly escaped in an interactive shell, e.g., as -GWIDTH=8\'hx. + +=item C integer literals + +It is also possible to use C integer notation, including hexadecimal (0x..), +octal (0..) or binary (0b..) notation. + +=item Double literals + +Double literals must contain a dot (.) and/or an exponent (e). + +=item Strings + +String must in double quotes ("). On the command line it is required to escape +them properly, e.g. as -GSTR="\"My String\"" or -GSTR='"My String"'. + +=back + =item --gdb Run Verilator underneath an interactive GDB (or VERILATOR_GDB environment @@ -946,6 +988,11 @@ inlining. This will also turn off inlining as if all modules had a /*verilator public_module*/, unless the module specifically enabled it with /*verilator inline_module*/. +=item -pvalue+I=I + +Overwrites the given parameter(s) of the toplevel module. See -G for a +detailed description. + =item --report-unoptflat Extra diagnostics for UNOPTFLAT warnings. This includes for each loop, the @@ -1340,7 +1387,7 @@ This is an example similar to the above, but using SystemC. top = new Vour("top"); // SP_CELL (top, Vour); top->clk(clk); // SP_PIN (top, clk, clk); while (!Verilated::gotFinish()) { sc_start(1, SC_NS); } - delete top; + delete top; exit(0); } EOF @@ -1603,7 +1650,7 @@ example: double sc_time_stamp () { // Called by $time in Verilog return main_time; // converts to double, to match - // what SystemC does + // what SystemC does } int main(int argc, char** argv) { @@ -1847,7 +1894,7 @@ accesses the above would be: if (!vh1) { error... } const char* name = vpi_get_str(vpiName, vh1); printf("Module name: %s\n"); // Prints "readme" - + s_vpi_value v; v.format = vpiIntVal; vpi_get_value(vh1, &v); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 663741f16..ded86a3f6 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -77,6 +77,7 @@ #include "V3SymTable.h" #include "V3Graph.h" #include "V3Ast.h" +#include "V3ParseImp.h" //###################################################################### // LinkDot state, as a visitor of each AstNode @@ -586,6 +587,42 @@ class LinkDotFindVisitor : public AstNVisitor { // METHODS int debug() { return LinkDotState::debug(); } + virtual AstConst* parseParamLiteral(FileLine* fl, string literal) { + bool success = false; + if (literal[0] == '"') { + // This is a string + string v = literal.substr(1, literal.find('"', 1) - 1); + V3Number n(V3Number::VerilogStringLiteral(), fl, v); + return new AstConst(fl,n); + } else if ((literal.find(".") != string::npos) + || (literal.find("e") != string::npos)) { + // This may be a real + double v = V3ParseImp::parseDouble(literal.c_str(), literal.length(), &success); + if (success) { + return new AstConst(fl, AstConst::RealDouble(), v); + } + } + if (!success) { + // This is either an integer or an error + // We first try to convert it as C literal. If strtol returns + // 0 this is either an error or 0 was parsed. But in any case + // we will try to parse it as a verilog literal, hence having + // the false negative for 0 is okay. If anything remains in + // the string after the number, this is invalid C and we try + // the Verilog literal parser. + char* endp; + int v = strtol(literal.c_str(), &endp, 0); + if ((v != 0) && (endp[0] == 0)) { // C literal + V3Number n(fl, 32, v); + return new AstConst(fl, n); + } else { // Try a Verilog literal (fatals if not) + V3Number n(fl, literal.c_str()); + return new AstConst(fl, n); + } + } + return NULL; + } + // VISITs virtual void visit(AstNetlist* nodep, AstNUser*) { // Process $unit or other packages @@ -873,6 +910,24 @@ class LinkDotFindVisitor : public AstNVisitor { } } if (ins) { + if (m_statep->forPrimary() && nodep->isGParam() + && (m_statep->rootEntp()->nodep() == m_modSymp->parentp()->nodep())) { + // This is the toplevel module. Check for command line overwrites of parameters + // We first search if the parameter is overwritten and then replace it with a + // new value. It will keep the same FileLine information. + if (v3Global.opt.hasParameter(nodep->name())) { + AstVar* newp = new AstVar(nodep->fileline(), AstVarType(AstVarType::GPARAM), + nodep->name(), nodep); + string svalue = v3Global.opt.parameter(nodep->name()); + if (AstNode* valuep = parseParamLiteral(nodep->fileline(), svalue)) { + newp->valuep(valuep); + UINFO(9," replace parameter "<replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep); + nodep = newp; + } + } + } VSymEnt* insp = m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); if (m_statep->forPrimary() && nodep->isGParam()) { m_paramNum++; diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 7e41bdcca..7fdb1730c 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -130,6 +130,52 @@ void V3Options::addDefine(const string& defline, bool allowPlus) { V3PreShell::defineCmdLine(def,value); } } +void V3Options::addParameter(const string& paramline, bool allowPlus) { + // Split +define+foo=value into the appropriate parts and parse + // Optional + says to allow multiple defines on the line + // + is not quotable, as other simulators do not allow that + string left = paramline; + while (left != "") { + string param = left; + string::size_type pos; + if (allowPlus && ((pos=left.find("+")) != string::npos)) { + left = left.substr(pos+1); + param.erase(pos); + } else { + left = ""; + } + string value; + if ((pos=param.find("=")) != string::npos) { + value = param.substr(pos+1); + param.erase(pos); + } + UINFO(4,"Add parameter"<second; + m_parameters.erase(m_parameters.find(name)); + return value; +} + +void V3Options::checkParameters() { + if (!m_parameters.empty()) { + stringstream msg; + msg << "Parameters from the command line were not found in the design:"; + for (map::iterator it = m_parameters.begin(); + it != m_parameters.end(); ++it) { + msg << " " << it->first; + } + v3fatal(msg.str()<= DebugSrcMap m_dumpTrees; // argument: --dump-treei-= + map m_parameters; // Parameters + bool m_preprocOnly; // main switch: -E bool m_makeDepend; // main switch: -MMD @@ -162,6 +164,7 @@ class V3Options { void addFuture(const string& flag); void addIncDirUser(const string& incdir); // User requested void addIncDirFallback(const string& incdir); // Low priority if not found otherwise + void addParameter(const string& paramline, bool allowPlus); void addLangExt(const string& langext, const V3LangCode& lc); void addLibExtV(const string& libext); void optimize(int level); @@ -279,6 +282,10 @@ class V3Options { const V3StringList& vFiles() const { return m_vFiles; } const V3LangCode& defaultLanguage() const { return m_defaultLanguage; } + bool hasParameter(string name); + string parameter(string name); + void checkParameters(); + bool isFuture(const string& flag) const; bool isLibraryFile(const string& filename) const; bool isClocker(const string& signame) const; diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 2b41fd1d6..15bf969f3 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -160,6 +160,8 @@ void process () { // Cross-link dotted hierarchical references V3LinkDot::linkDotPrimary(v3Global.rootp()); v3Global.checkTree(); // Force a check, as link is most likely place for problems + // Check if all parameters have been found + v3Global.opt.checkParameters(); // Correct state we couldn't know at parse time, repair SEL's V3LinkResolve::linkResolve(v3Global.rootp()); // Set Lvalue's in variable refs diff --git a/test_regress/t/t_flag_parameter.pl b/test_regress/t/t_flag_parameter.pl new file mode 100755 index 000000000..1271079bb --- /dev/null +++ b/test_regress/t/t_flag_parameter.pl @@ -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 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 ( + # It is not possible to put them into the options file + v_flags2 => ['-Gstring1="\"New String\"" -pvalue+string2="\"New String\"" -f t/t_flag_parameter.vc'], + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_parameter.v b/test_regress/t/t_flag_parameter.v new file mode 100644 index 000000000..77dd585e3 --- /dev/null +++ b/test_regress/t/t_flag_parameter.v @@ -0,0 +1,49 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2016 by Wilson Snyder + +`define check(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: Wrong parameter value", `__FILE__,`__LINE__); $stop; end while(0); + +module t; + parameter string1 = "Original String"; + parameter string2 = "Original String"; + + parameter real11 = 0.1; + parameter real12 = 0.1; + parameter real21 = 0.1; + parameter real22 = 0.1; + parameter real31 = 0.1; + parameter real32 = 0.1; + + parameter int11 = 1; + parameter int12 = 1; + parameter int21 = 1; + parameter int22 = 1; + parameter int31 = 1; + parameter int32 = 1; + parameter int41 = 1; + parameter int42 = 1; + + initial begin + `check(string1,"New String"); + `check(string2,"New String"); + `check(real11,0.2); + `check(real12,0.2); + `check(real21,400); + `check(real22,400); + `check(real31,20); + `check(real32,20); + `check(int11,16); + `check(int12,16); + `check(int21,16); + `check(int22,16); + `check(int31,123); + `check(int32,123); + `check(int41,32'hdeadbeef); + `check(int42,32'hdeadbeef); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_flag_parameter.vc b/test_regress/t/t_flag_parameter.vc new file mode 100644 index 000000000..a51adbe3e --- /dev/null +++ b/test_regress/t/t_flag_parameter.vc @@ -0,0 +1,15 @@ +-Greal11=0.2 +-pvalue+real12=0.2 +-Greal21=4e2 +-pvalue+real22=4e2 +-Greal31=0.2e2 +-pvalue+real32=0.2e2 +-Gint11=0x10 +-pvalue+int12=0x10 +-Gint21=020 +-pvalue+int22=020 +-Gint31=123 +-pvalue+int32=123 +-Gint41=32'hdead_beef +-pvalue+int42=32'hdead_beef +