Add function to define parameter from command line

This patch is based on one from "bruce <bruce1914@gmail.com>".
I've applied all but the elaboration code, which I rewrote to
properly work with the elaboration work queue. I also constrained
the implementation so that the parameter name must have exactly
two components: the root scope name and the parameter name. This
is necessary to keep the defparm processing sane. The comments
from bruce's original patch are as follows:
--
This patch would provide function to define parameter from command
line. This serves the same functionality as 'defparam' in Verilog
source code, but provide much more ease for using. Parameter
definition can be write in command file, with following syntax:

    +parameter+<scope>.<parameter>=<val>

*Do not apply any space between them*
The scope name should be full hierachical name with root name at
the begining. The following example would override test.T1 with
new value 2'b01:

    +parameter+test.T1=2'b01

'test' here is the root module name. The parameter value here
should be constant. Parameter definition can also be write in
the command line:

    iverilog -Ptest.T1=2'b01

This serves the same functionality with the previous example.
If we define the same parameter in command file and command line,
the one in command line would over-write all others.
This commit is contained in:
Stephen Williams 2009-08-06 14:42:13 -07:00
parent 37b11e0355
commit 7b102b18fd
12 changed files with 236 additions and 17 deletions

View File

@ -24,6 +24,8 @@
# include "PWire.h" # include "PWire.h"
# include <assert.h> # include <assert.h>
list<Module::named_expr_t> Module::user_defparms;
/* n is a permallocated string. */ /* n is a permallocated string. */
Module::Module(perm_string n) Module::Module(perm_string n)
: PScope(n) : PScope(n)

View File

@ -92,6 +92,7 @@ class Module : public PScope, public LineInfo {
instantiated modules. */ instantiated modules. */
typedef pair<pform_name_t,PExpr*> named_expr_t; typedef pair<pform_name_t,PExpr*> named_expr_t;
list<named_expr_t>defparms; list<named_expr_t>defparms;
static list<named_expr_t>user_defparms;
/* Parameters may be overridden at instantiation time; /* Parameters may be overridden at instantiation time;
the overrides do not contain explicit parameter names, the overrides do not contain explicit parameter names,

View File

@ -72,6 +72,8 @@ int cmdfile_stack_ptr = 0;
\n { cflloc.first_line += 1; } \n { cflloc.first_line += 1; }
"+parameter+" { BEGIN(PLUS_ARGS); return TOK_PARAMETER; }
"+define+" { BEGIN(PLUS_ARGS); return TOK_DEFINE; } "+define+" { BEGIN(PLUS_ARGS); return TOK_DEFINE; }
"+incdir+" { BEGIN(PLUS_ARGS); return TOK_INCDIR; } "+incdir+" { BEGIN(PLUS_ARGS); return TOK_INCDIR; }

View File

@ -57,7 +57,7 @@ static void translate_file_name(char*text)
}; };
%token TOK_Da TOK_Dc TOK_Dv TOK_Dy %token TOK_Da TOK_Dc TOK_Dv TOK_Dy
%token TOK_DEFINE TOK_INCDIR TOK_LIBDIR TOK_LIBDIR_NOCASE TOK_LIBEXT %token TOK_DEFINE TOK_INCDIR TOK_LIBDIR TOK_LIBDIR_NOCASE TOK_LIBEXT TOK_PARAMETER
%token TOK_INTEGER_WIDTH %token TOK_INTEGER_WIDTH
%token <text> TOK_PLUSARG TOK_PLUSWORD TOK_STRING %token <text> TOK_PLUSARG TOK_PLUSWORD TOK_STRING
@ -135,6 +135,13 @@ item
free(tmp); free(tmp);
} }
| TOK_PARAMETER TOK_PLUSARG
{ char*tmp = substitutions($2);
process_parameter(tmp);
free($2);
free(tmp);
}
| TOK_DEFINE TOK_PLUSARG | TOK_DEFINE TOK_PLUSARG
{ process_define($2); { process_define($2);
free($2); free($2);

View File

@ -66,6 +66,9 @@ extern void process_include_dir(const char*name);
/* Add a new -D define. */ /* Add a new -D define. */
extern void process_define(const char*name); extern void process_define(const char*name);
/* Add a new parameter definition */
extern void process_parameter(const char*name);
/* -v */ /* -v */
extern int verbose_flag; extern int verbose_flag;

View File

@ -167,6 +167,12 @@ typedef struct t_command_file {
p_command_file cmd_file_head = NULL; /* The FIFO head */ p_command_file cmd_file_head = NULL; /* The FIFO head */
p_command_file cmd_file_tail = NULL; /* The FIFO tail */ p_command_file cmd_file_tail = NULL; /* The FIFO tail */
/* Temprarily store parameter definition from command line and
* parse it after we have delt with command file
*/
static const char** defparm_base = 0;
static int defparm_size = 0;
/* Function to add a command file name to the FIFO. */ /* Function to add a command file name to the FIFO. */
void add_cmd_file(const char* filename) void add_cmd_file(const char* filename)
{ {
@ -530,6 +536,11 @@ void process_define(const char*name)
fprintf(defines_file,"D:%s\n", name); fprintf(defines_file,"D:%s\n", name);
} }
void process_parameter(const char*name)
{
fprintf(iconfig_file,"defparam:%s\n", name);
}
/* /*
* This function is called while processing a file name in a command * This function is called while processing a file name in a command
* file, or a file name on the command line. Look to see if there is a * file, or a file name on the command line. Look to see if there is a
@ -774,7 +785,7 @@ int main(int argc, char **argv)
} }
} }
while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hI:M:m:N::o:p:Ss:T:t:vVW:y:Y:")) != EOF) { while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hI:M:m:N::o:P:p:Ss:T:t:vVW:y:Y:")) != EOF) {
switch (opt) { switch (opt) {
case 'B': case 'B':
@ -798,6 +809,11 @@ int main(int argc, char **argv)
case 'E': case 'E':
e_flag = 1; e_flag = 1;
break; break;
case 'P':
defparm_size += 1;
defparm_base = (const char**)realloc(defparm_base, defparm_size*sizeof(char*));
defparm_base[defparm_size-1] = optarg;
break;
case 'p': case 'p':
fprintf(iconfig_file, "flag:%s\n", optarg); fprintf(iconfig_file, "flag:%s\n", optarg);
break; break;
@ -966,6 +982,15 @@ int main(int argc, char **argv)
fprintf(defines_file, "M:%s\n", depfile); fprintf(defines_file, "M:%s\n", depfile);
} }
/* Process parameter definition from command line. The last
defined would override previous ones. */
int pitr;
for (pitr = 0; pitr < defparm_size; pitr++)
process_parameter(defparm_base[pitr]);
free(defparm_base);
defparm_base = 0;
defparm_size = 0;
/* Finally, process all the remaining words on the command /* Finally, process all the remaining words on the command
line as file names. */ line as file names. */
for (idx = optind ; idx < argc ; idx += 1) for (idx = optind ; idx < argc ; idx += 1)

View File

@ -4226,8 +4226,23 @@ class elaborate_root_scope_t : public elaborator_work_item_t {
virtual void elaborate_runrun() virtual void elaborate_runrun()
{ {
Module::replace_t stub; Module::replace_t root_repl;
if (! rmod_->elaborate_scope(des, scope_, stub)) for (list<Module::named_expr_t>::iterator cur = Module::user_defparms.begin()
; cur != Module::user_defparms.end() ; cur++) {
pform_name_t tmp_name = cur->first;
if (peek_head_name(tmp_name) != scope_->basename())
continue;
tmp_name.pop_front();
if (tmp_name.size() != 1)
continue;
NetExpr*tmp_expr = cur->second->elaborate_pexpr(des, scope_);
root_repl[peek_head_name(tmp_name)] = tmp_expr;
}
if (! rmod_->elaborate_scope(des, scope_, root_repl))
des->errors += 1; des->errors += 1;
} }

View File

@ -71,11 +71,11 @@ void reset_lexor();
static void line_directive(); static void line_directive();
static void line_directive2(); static void line_directive2();
static verinum*make_unsized_binary(const char*txt); verinum*make_unsized_binary(const char*txt);
static verinum*make_undef_highz_dec(const char*txt); verinum*make_undef_highz_dec(const char*txt);
static verinum*make_unsized_dec(const char*txt); verinum*make_unsized_dec(const char*txt);
static verinum*make_unsized_octal(const char*txt); verinum*make_unsized_octal(const char*txt);
static verinum*make_unsized_hex(const char*txt); verinum*make_unsized_hex(const char*txt);
static int dec_buf_div2(char *buf); static int dec_buf_div2(char *buf);
@ -667,7 +667,7 @@ void lex_end_table()
BEGIN(INITIAL); BEGIN(INITIAL);
} }
static verinum*make_unsized_binary(const char*txt) verinum*make_unsized_binary(const char*txt)
{ {
bool sign_flag = false; bool sign_flag = false;
const char*ptr = txt; const char*ptr = txt;
@ -725,7 +725,7 @@ static verinum*make_unsized_binary(const char*txt)
} }
static verinum*make_unsized_octal(const char*txt) verinum*make_unsized_octal(const char*txt)
{ {
bool sign_flag = false; bool sign_flag = false;
const char*ptr = txt; const char*ptr = txt;
@ -792,7 +792,7 @@ static verinum*make_unsized_octal(const char*txt)
} }
static verinum*make_unsized_hex(const char*txt) verinum*make_unsized_hex(const char*txt)
{ {
bool sign_flag = false; bool sign_flag = false;
const char*ptr = txt; const char*ptr = txt;
@ -919,7 +919,7 @@ static int dec_buf_div2(char *buf)
} }
/* Support a single x, z or ? as a decimal constant (from 1364-2005). */ /* Support a single x, z or ? as a decimal constant (from 1364-2005). */
static verinum* make_undef_highz_dec(const char* ptr) verinum* make_undef_highz_dec(const char* ptr)
{ {
bool signed_flag = false; bool signed_flag = false;
@ -972,7 +972,7 @@ static verinum* make_undef_highz_dec(const char* ptr)
* hard to calculate. * hard to calculate.
*/ */
static verinum*make_unsized_dec(const char*ptr) verinum*make_unsized_dec(const char*ptr)
{ {
char buf[4096]; char buf[4096];
bool signed_flag = false; bool signed_flag = false;

View File

@ -528,7 +528,8 @@ static void read_iconfig_file(const char*ipath)
<< endl; << endl;
flag_errors += 1; flag_errors += 1;
} }
} else if (strcmp(buf,"defparam") == 0) {
parm_to_defparam_list(cp);
} }
} }
fclose(ifile); fclose(ifile);

View File

@ -77,4 +77,14 @@ extern UCDriveType uc_drive;
extern bool have_timeunit_decl; extern bool have_timeunit_decl;
extern bool have_timeprec_decl; extern bool have_timeprec_decl;
/*
* Export there functions because we have to generate PENumber class
* in pform.cc for user defparam definition from command file.
*/
extern verinum*make_unsized_dec(const char*txt);
extern verinum*make_undef_highz_dec(const char*txt);
extern verinum*make_unsized_binary(const char*txt);
extern verinum*make_unsized_octal(const char*txt);
extern verinum*make_unsized_hex(const char*txt);
#endif #endif

145
pform.cc
View File

@ -42,6 +42,151 @@
map<perm_string,Module*> pform_modules; map<perm_string,Module*> pform_modules;
map<perm_string,PUdp*> pform_primitives; map<perm_string,PUdp*> pform_primitives;
/*
* Parse configuration file with format <key>=<value>, where key
* is the hierarchical name of a valid parameter name, and value
* is the value user wants to assign to. The value should be constant.
*/
void parm_to_defparam_list(const string&param)
{
const char* key;
const char* value;
unsigned off = param.find('=');
if (off > param.size()) {
key = strdup(param.c_str());
value = "";
} else {
key = strdup(param.substr(0, off).c_str());
value = strdup(param.substr(off+1).c_str());
}
// Resolve hierarchical name for defparam. Remember
// to deal with bit select for generate scopes. Bit
// select expression should be constant interger.
pform_name_t name;
const char *nkey = key;
char *ptr = strchr(key, '.');
while (ptr != 0) {
*ptr++ = '\0';
// Find if bit select is applied, this would be something
// like - scope[2].param = 10
char *bit_l = strchr(nkey, '[');
if (bit_l !=0) {
*bit_l++ = '\0';
char *bit_r = strchr(bit_l, ']');
if (bit_r == 0) {
cerr << "<command line>: error: missing ']' for defparam: " << nkey << endl;
return;
}
*bit_r = '\0';
int i = 0;
while (*(bit_l+i) != '\0')
if (!isdigit(*(bit_l+i++))) {
cerr << "<command line>: error: scope index expression is not constant: " << nkey << endl;
return;
}
name_component_t tmp(lex_strings.make(nkey));
index_component_t index;
index.sel = index_component_t::SEL_BIT;
verinum *seln = new verinum(atoi(bit_l));
PENumber *sel = new PENumber(seln);
index.msb = sel;
index.lsb = sel;
tmp.index.push_back(index);
name.push_back(tmp);
}
else // no bit select
name.push_back(name_component_t(lex_strings.make(nkey)));
nkey = ptr;
ptr = strchr(nkey, '.');
}
name.push_back(name_component_t(lex_strings.make(nkey)));
// Resolve value to PExpr class. Should support all kind of constant
// format including based number, dec number, real number and string.
if (*value == '"') { // string type
char *buf = strdup (value);
char *buf_ptr = buf+1;
// Parse untill another '"' or '\0'
while (*buf_ptr != '"' && *buf_ptr != '\0') {
buf_ptr++;
// Check for escape, especially '\"', which does not mean the
// end of string.
if (*buf_ptr == '\\' && *(buf_ptr+1) != '\0')
buf_ptr += 2;
}
if (*buf_ptr == '\0') // String end without '"'
cerr << "<command line>: error: missing close quote of string for defparam: " << name << endl;
else if (*(buf_ptr+1) != 0) { // '"' appears within string with no escape
cerr << buf_ptr << endl;
cerr << "<command line>: error: \'\"\' appears within string value for defparam: " << name
<< ". Ignore characters after \'\"\'" << endl;
}
*buf_ptr = '\0';
buf_ptr = buf+1;
// Remember to use 'new' to allocate string for PEString
// because 'delete' is used by its destructor.
char *nchar = strcpy(new char [strlen(buf_ptr)+1], buf_ptr);
PEString* ndec = new PEString(nchar);
Module::user_defparms.push_back( make_pair(name, ndec) );
free(buf);
}
else { // number type
char *num = strchr(value, '\'');
if (num != 0) {
verinum *val;
// BASED_NUMBER, somthing like - scope.parameter='b11
// make sure to check 'h' first because 'b'&'d' may be included
// in hex format
if (strchr(num, 'h') || strchr(num, 'H'))
val = make_unsized_hex(num);
else if (strchr(num, 'd') || strchr(num, 'D'))
if (strchr(num, 'x') || strchr(num, 'X') || strchr(num, 'z') || strchr(num, 'Z'))
val = make_undef_highz_dec(num);
else
val = make_unsized_dec(num);
else if (strchr(num, 'b') || strchr(num, 'B')) {
val = make_unsized_binary(num);
}
else if (strchr(num, 'o') || strchr(num, 'O'))
val = make_unsized_octal(num);
else {
cerr << "<command line>: error: value specify error for defparam: " << name << endl;
return;
}
// BASED_NUMBER with size, something like - scope.parameter=2'b11
if (num != value) {
*num = 0;
verinum *siz = make_unsized_dec(value);
val = pform_verinum_with_size(siz, val, "<command line>", 0);
}
PENumber* ndec = new PENumber(val);
Module::user_defparms.push_back( make_pair(name, ndec) );
}
else {
// REALTIME, something like - scope.parameter=1.22 or scope.parameter=1e2
if (strchr(value, '.') || strchr(value, 'e') || strchr(value, 'E')) {
verireal *val = new verireal(value);
PEFNumber* nreal = new PEFNumber(val);
Module::user_defparms.push_back( make_pair(name, nreal) );
}
else {
// DEC_NUMBER, something like - scope.parameter=3
verinum *val = make_unsized_dec(value);
PENumber* ndec = new PENumber(val);
Module::user_defparms.push_back( make_pair(name, ndec) );
}
}
}
}
/* /*
* The lexor accesses the vl_* variables. * The lexor accesses the vl_* variables.
*/ */

View File

@ -410,6 +410,14 @@ extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc,
extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc,
char*name, char*branch); char*name, char*branch);
/*
* Parse configuration file with format <key>=<value>, where key
* is the hierarchical name of a valid parameter name and value
* is the value user wants to assign to. The value should be constant.
*/
extern void parm_to_defparam_list(const string&param);
/* /*
* Tasks to set the timeunit or timeprecision for SystemVerilog. * Tasks to set the timeunit or timeprecision for SystemVerilog.
*/ */