From 7b102b18fd3837899ae1ceecfb770a61b693c64b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 6 Aug 2009 14:42:13 -0700 Subject: [PATCH] Add function to define parameter from command line This patch is based on one from "bruce ". 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+.= *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. --- Module.cc | 2 + Module.h | 1 + driver/cflexor.lex | 2 + driver/cfparse.y | 9 ++- driver/globals.h | 5 +- driver/main.c | 27 ++++++++- elaborate.cc | 19 +++++- lexor.lex | 20 +++---- main.cc | 5 +- parse_misc.h | 10 ++++ pform.cc | 145 +++++++++++++++++++++++++++++++++++++++++++++ pform.h | 8 +++ 12 files changed, 236 insertions(+), 17 deletions(-) diff --git a/Module.cc b/Module.cc index 774dfdbf76..6fa6fcdf91 100644 --- a/Module.cc +++ b/Module.cc @@ -24,6 +24,8 @@ # include "PWire.h" # include +list Module::user_defparms; + /* n is a permallocated string. */ Module::Module(perm_string n) : PScope(n) diff --git a/Module.h b/Module.h index 80d43031ac..b9f179d174 100644 --- a/Module.h +++ b/Module.h @@ -92,6 +92,7 @@ class Module : public PScope, public LineInfo { instantiated modules. */ typedef pair named_expr_t; listdefparms; + static listuser_defparms; /* Parameters may be overridden at instantiation time; the overrides do not contain explicit parameter names, diff --git a/driver/cflexor.lex b/driver/cflexor.lex index 526f8eaed4..8e3277d22a 100644 --- a/driver/cflexor.lex +++ b/driver/cflexor.lex @@ -72,6 +72,8 @@ int cmdfile_stack_ptr = 0; \n { cflloc.first_line += 1; } +"+parameter+" { BEGIN(PLUS_ARGS); return TOK_PARAMETER; } + "+define+" { BEGIN(PLUS_ARGS); return TOK_DEFINE; } "+incdir+" { BEGIN(PLUS_ARGS); return TOK_INCDIR; } diff --git a/driver/cfparse.y b/driver/cfparse.y index 9ee38e7d3f..9572484d14 100644 --- a/driver/cfparse.y +++ b/driver/cfparse.y @@ -57,7 +57,7 @@ static void translate_file_name(char*text) }; %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_PLUSARG TOK_PLUSWORD TOK_STRING @@ -135,6 +135,13 @@ item free(tmp); } + | TOK_PARAMETER TOK_PLUSARG + { char*tmp = substitutions($2); + process_parameter(tmp); + free($2); + free(tmp); + } + | TOK_DEFINE TOK_PLUSARG { process_define($2); free($2); diff --git a/driver/globals.h b/driver/globals.h index 0cc16728b0..e78f00e834 100644 --- a/driver/globals.h +++ b/driver/globals.h @@ -65,7 +65,10 @@ extern void process_include_dir(const char*name); /* Add a new -D define. */ extern void process_define(const char*name); - + + /* Add a new parameter definition */ +extern void process_parameter(const char*name); + /* -v */ extern int verbose_flag; diff --git a/driver/main.c b/driver/main.c index f7a7574d0f..c45d837b00 100644 --- a/driver/main.c +++ b/driver/main.c @@ -167,6 +167,12 @@ typedef struct t_command_file { p_command_file cmd_file_head = NULL; /* The FIFO head */ 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. */ void add_cmd_file(const char* filename) { @@ -530,6 +536,11 @@ void process_define(const char*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 * 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) { case 'B': @@ -798,6 +809,11 @@ int main(int argc, char **argv) case 'E': e_flag = 1; 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': fprintf(iconfig_file, "flag:%s\n", optarg); break; @@ -966,6 +982,15 @@ int main(int argc, char **argv) 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 line as file names. */ for (idx = optind ; idx < argc ; idx += 1) diff --git a/elaborate.cc b/elaborate.cc index 3061aa1445..1ef37368a5 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4226,8 +4226,23 @@ class elaborate_root_scope_t : public elaborator_work_item_t { virtual void elaborate_runrun() { - Module::replace_t stub; - if (! rmod_->elaborate_scope(des, scope_, stub)) + Module::replace_t root_repl; + for (list::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; } diff --git a/lexor.lex b/lexor.lex index 9e8504c66b..66c99dfa68 100644 --- a/lexor.lex +++ b/lexor.lex @@ -71,11 +71,11 @@ void reset_lexor(); static void line_directive(); static void line_directive2(); -static verinum*make_unsized_binary(const char*txt); -static verinum*make_undef_highz_dec(const char*txt); -static verinum*make_unsized_dec(const char*txt); -static verinum*make_unsized_octal(const char*txt); -static verinum*make_unsized_hex(const char*txt); +verinum*make_unsized_binary(const char*txt); +verinum*make_undef_highz_dec(const char*txt); +verinum*make_unsized_dec(const char*txt); +verinum*make_unsized_octal(const char*txt); +verinum*make_unsized_hex(const char*txt); static int dec_buf_div2(char *buf); @@ -667,7 +667,7 @@ void lex_end_table() BEGIN(INITIAL); } -static verinum*make_unsized_binary(const char*txt) +verinum*make_unsized_binary(const char*txt) { bool sign_flag = false; 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; 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; 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). */ -static verinum* make_undef_highz_dec(const char* ptr) +verinum* make_undef_highz_dec(const char* ptr) { bool signed_flag = false; @@ -972,7 +972,7 @@ static verinum* make_undef_highz_dec(const char* ptr) * hard to calculate. */ -static verinum*make_unsized_dec(const char*ptr) +verinum*make_unsized_dec(const char*ptr) { char buf[4096]; bool signed_flag = false; diff --git a/main.cc b/main.cc index c80b2baede..5c58b7a711 100644 --- a/main.cc +++ b/main.cc @@ -528,8 +528,9 @@ static void read_iconfig_file(const char*ipath) << endl; flag_errors += 1; } - - } + } else if (strcmp(buf,"defparam") == 0) { + parm_to_defparam_list(cp); + } } fclose(ifile); } diff --git a/parse_misc.h b/parse_misc.h index c49cb1652f..40efbfffae 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -77,4 +77,14 @@ extern UCDriveType uc_drive; extern bool have_timeunit_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 diff --git a/pform.cc b/pform.cc index 9c2660f469..9041e70ec9 100644 --- a/pform.cc +++ b/pform.cc @@ -42,6 +42,151 @@ map pform_modules; map pform_primitives; + +/* + * Parse configuration file with format =, 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¶m) +{ + 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 << ": error: missing ']' for defparam: " << nkey << endl; + return; + } + *bit_r = '\0'; + int i = 0; + while (*(bit_l+i) != '\0') + if (!isdigit(*(bit_l+i++))) { + cerr << ": 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 << ": 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 << ": 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 << ": 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, "", 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. */ diff --git a/pform.h b/pform.h index 778d748d30..c2a49097ae 100644 --- a/pform.h +++ b/pform.h @@ -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, char*name, char*branch); + +/* + * Parse configuration file with format =, 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¶m); + /* * Tasks to set the timeunit or timeprecision for SystemVerilog. */