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. */