Support command-line -G/+pvalue param overrides, bug1045.

Signed-off-by: Wilson Snyder <wsnyder@wsnyder.org>
This commit is contained in:
Stefan Wallentowitz 2016-03-24 19:14:15 -04:00 committed by Wilson Snyder
parent b2623b9841
commit 482bdab0e0
9 changed files with 251 additions and 4 deletions

View File

@ -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

View File

@ -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 <file> Parse options from a file, relatively
-f <file> Parse options from a file
-G<name>=<value> 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+<name>=<value> 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<name>=I<value>
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<name>=I<value>
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);

View File

@ -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 "<<nodep<<endl);
UINFO(9," with "<<newp<<endl);
nodep->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++;

View File

@ -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"<<param<<"="<<value<<endl);
(void)m_parameters.erase(param);
m_parameters[param] = value;
}
}
bool V3Options::hasParameter(string name) {
return m_parameters.find(name) != m_parameters.end();
}
string V3Options::parameter(string name) {
string value = m_parameters.find(name)->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<string,string>::iterator it = m_parameters.begin();
it != m_parameters.end(); ++it) {
msg << " " << it->first;
}
v3fatal(msg.str()<<endl);
}
}
void V3Options::addCppFile(const string& filename) {
if (m_cppFiles.find(filename) == m_cppFiles.end()) {
@ -658,6 +704,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( !strcmp (sw, "-private") ) { m_public = false; }
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/) ) { m_profileCFuncs = flag; }
else if ( onoff (sw, "-public", flag/*ref*/) ) { m_public = flag; }
else if ( !strncmp(sw, "-pvalue+", strlen("-pvalue+"))) { addParameter(string(sw+strlen("-pvalue+")), false); }
else if ( onoff (sw, "-report-unoptflat", flag/*ref*/) ) { m_reportUnoptflat = flag; }
else if ( onoff (sw, "-savable", flag/*ref*/) ) { m_savable = flag; }
else if ( !strcmp (sw, "-sc") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = false; }
@ -748,6 +795,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
shift;
V3Error::errorLimit(atoi(argv[i]));
}
else if ( !strncmp (sw, "-G", strlen("-G"))) {
addParameter (string (sw+strlen("-G")), false);
}
else if ( !strncmp (sw, "-I", 2)) {
addIncDirUser (parseFileArg(optdir, string (sw+strlen("-I"))));
}

View File

@ -58,6 +58,8 @@ class V3Options {
V3StringList m_vFiles; // argument: Verilog files to read
DebugSrcMap m_debugSrcs; // argument: --debugi-<srcfile>=<level>
DebugSrcMap m_dumpTrees; // argument: --dump-treei-<srcfile>=<level>
map<string,string> 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;

View File

@ -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

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 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;

View File

@ -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

View File

@ -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