Permalink
Browse files

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.
  • Loading branch information...
1 parent 37b11e0 commit 7b102b18fd3837899ae1ceecfb770a61b693c64b @steveicarus committed Aug 6, 2009
Showing with 236 additions and 17 deletions.
  1. +2 −0 Module.cc
  2. +1 −0 Module.h
  3. +2 −0 driver/cflexor.lex
  4. +8 −1 driver/cfparse.y
  5. +4 −1 driver/globals.h
  6. +26 −1 driver/main.c
  7. +17 −2 elaborate.cc
  8. +10 −10 lexor.lex
  9. +3 −2 main.cc
  10. +10 −0 parse_misc.h
  11. +145 −0 pform.cc
  12. +8 −0 pform.h
View
@@ -24,6 +24,8 @@
# include "PWire.h"
# include <assert.h>
+list<Module::named_expr_t> Module::user_defparms;
+
/* n is a permallocated string. */
Module::Module(perm_string n)
: PScope(n)
View
@@ -92,6 +92,7 @@ class Module : public PScope, public LineInfo {
instantiated modules. */
typedef pair<pform_name_t,PExpr*> named_expr_t;
list<named_expr_t>defparms;
+ static list<named_expr_t>user_defparms;
/* Parameters may be overridden at instantiation time;
the overrides do not contain explicit parameter names,
View
@@ -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; }
View
@@ -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 <text> 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);
View
@@ -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;
View
@@ -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)
View
@@ -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<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;
}
View
@@ -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;
View
@@ -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);
}
View
@@ -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
View
145 pform.cc
@@ -42,6 +42,151 @@
map<perm_string,Module*> pform_modules;
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.
*/
Oops, something went wrong.

0 comments on commit 7b102b1

Please sign in to comment.