diff --git a/Module.h b/Module.h index 09932947a..daca15078 100644 --- a/Module.h +++ b/Module.h @@ -94,10 +94,14 @@ class Module : public PScope, public LineInfo { module is elaborated. During parsing, I put the parameters into this map. */ struct param_expr_t : public LineInfo { - PExpr*expr; + param_expr_t() : range(0) { } + // Type information + ivl_variable_type_t type; PExpr*msb; PExpr*lsb; bool signed_flag; + // Value expression + PExpr*expr; // If there are range constrants, list them here range_t*range; }; diff --git a/design_dump.cc b/design_dump.cc index 1e8fddbf7..3c00083a8 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1290,11 +1290,9 @@ void NetESignal::dump(ostream&o) const void NetEParam::dump(ostream&o) const { if (scope_ != 0) - o << "<" << scope_path(scope_) << "." << name_ << ">"; - else if (name_) - o << "<" << name_ << ">"; + o << "<" << scope_path(scope_) << "." << (*reference_).first << ">"; else - o << "<" "???" ">"; + o << "<" << (*reference_).first << ">"; } void NetETernary::dump(ostream&o) const diff --git a/elab_scope.cc b/elab_scope.cc index d2619d20a..00f564b10 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -63,9 +63,11 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur, parameter value is coerced to have the correct and defined width. */ if (cur.msb) { + assert(cur.lsb); msb = cur.msb ->elaborate_pexpr(des, scope); assert(msb); lsb = cur.lsb ->elaborate_pexpr(des, scope); + assert(lsb); } if (signed_flag) { @@ -102,7 +104,7 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur, range_list = tmp; } - val = scope->set_parameter(name, val, msb, lsb, signed_flag, range_list, cur); + val = scope->set_parameter(name, val, cur.type, msb, lsb, signed_flag, range_list, cur); assert(val); delete val; } @@ -140,7 +142,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, tmp->set_line(*((*cur).second.expr)); tmp->cast_signed( (*cur).second.signed_flag ); - scope->set_parameter((*cur).first, tmp, 0, 0, false, 0, (*cur).second); + scope->set_parameter((*cur).first, tmp, (*cur).second.type, + 0, 0, false, 0, (*cur).second); } for (mparm_it_t cur = localparams.begin() @@ -151,7 +154,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, if ((*cur).second.msb) tmp->cast_signed( (*cur).second.signed_flag ); - scope->set_parameter((*cur).first, tmp, 0, 0, false, 0, (*cur).second); + scope->set_parameter((*cur).first, tmp, (*cur).second.type, + 0, 0, false, 0, (*cur).second); } @@ -183,6 +187,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, << "Replace " << (*cur).first << " with expression " << *val << " from " << val->get_fileline() << "." << endl; + cerr << get_fileline() << ": : " + << "Type=" << val->expr_type() << endl; } bool flag = scope->replace_parameter((*cur).first, val); if (! flag) { diff --git a/eval_tree.cc b/eval_tree.cc index f6608e7b7..b2ac5cb63 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1171,17 +1171,11 @@ NetExpr* NetEParam::eval_tree(int prune_to_width) } assert(scope_); - const NetExpr*expr_msb; - const NetExpr*expr_lsb; - const NetExpr*expr = scope_->get_parameter(name_, expr_msb, expr_lsb); - if (expr == 0) { - cerr << get_fileline() << ": internal error: Unable to match " - << "parameter " << name_ << " in scope " - << scope_path(scope_) << endl; - return 0; - } - - assert(expr); + perm_string name = (*reference_).first; + const NetExpr*expr_msb = (*reference_).second.msb; + const NetExpr*expr_lsb = (*reference_).second.lsb; + const NetExpr*expr = (*reference_).second.expr; + ivl_assert(*this, expr); NetExpr*nexpr = expr->dup_expr(); assert(nexpr); @@ -1190,7 +1184,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width) // return the constant value. if (NetEConst*tmp = dynamic_cast(nexpr)) { verinum val = tmp->value(); - NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val); + NetEConstParam*ptmp = new NetEConstParam(scope_, name, val); ptmp->set_line(*this); delete nexpr; return ptmp; @@ -1198,7 +1192,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width) if (NetECReal*tmp = dynamic_cast(nexpr)) { verireal val = tmp->value(); - NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val); + NetECRealParam*ptmp = new NetECRealParam(scope_, name, val); ptmp->set_line(*this); delete nexpr; return ptmp; @@ -1209,7 +1203,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width) NetExpr*res = nexpr->eval_tree(); if (res == 0) { cerr << get_fileline() << ": internal error: Unable to evaluate " - << "parameter " << name_ << " expression: " + << "parameter " << name << " expression: " << *nexpr << endl; delete nexpr; return 0; @@ -1217,10 +1211,10 @@ NetExpr* NetEParam::eval_tree(int prune_to_width) // The result can be saved as the value of the parameter for // future reference, and return a copy to the caller. - bool flag = scope_->replace_parameter(name_, res); + bool flag = scope_->replace_parameter(name, res); if (!flag) { cerr << get_fileline() << ": internal error: Could not " - << "replace parameter expression for " << name_ << endl; + << "replace parameter expression for " << name << endl; return 0; } @@ -1234,7 +1228,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width) { NetEConst*tmp = dynamic_cast(res); if (tmp == 0) { cerr << get_fileline() << ": internal error: parameter " - << name_ << " evaluates to incomprehensible " + << name << " evaluates to incomprehensible " << *res << "." << endl; return 0; } @@ -1242,7 +1236,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width) assert(tmp); verinum val = tmp->value(); - NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val); + NetEConstParam*ptmp = new NetEConstParam(scope_, name, val); return ptmp; } @@ -1251,7 +1245,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width) { NetECReal*tmp = dynamic_cast(res); if (tmp == 0) { cerr << get_fileline() << ": internal error: parameter " - << name_ << " evaluates to incomprehensible " + << name << " evaluates to incomprehensible " << *res << "." << endl; return 0; } @@ -1259,7 +1253,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width) assert(tmp); verireal val = tmp->value(); - NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val); + NetECRealParam*ptmp = new NetECRealParam(scope_, name, val); return ptmp; } diff --git a/net_design.cc b/net_design.cc index 2d02ee3b0..4050be8d0 100644 --- a/net_design.cc +++ b/net_design.cc @@ -243,6 +243,253 @@ void Design::evaluate_parameters() (*scope)->evaluate_parameters(this); } +void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) +{ + long msb = 0; + long lsb = 0; + bool range_flag = false; + + /* Evaluate the msb expression, if it is present. */ + if ((*cur).second.msb) { + eval_expr((*cur).second.msb); + if (! eval_as_long(msb, (*cur).second.msb)) { + cerr << (*cur).second.expr->get_fileline() + << ": internal error: " + << "unable to evaluate msb expression " + << "for parameter " << (*cur).first << ": " + << *(*cur).second.msb << endl; + des->errors += 1; + return; + } + + range_flag = true; + } + + /* Evaluate the lsb expression, if it is present. */ + if ((*cur).second.lsb) { + eval_expr((*cur).second.lsb); + if (! eval_as_long(lsb, (*cur).second.lsb)) { + cerr << (*cur).second.expr->get_fileline() + << ": internal error: " + << "unable to evaluate lsb expression " + << "for parameter " << (*cur).first << ": " + << *(*cur).second.lsb << endl; + des->errors += 1; + return; + } + + range_flag = true; + } + + + /* Evaluate the parameter expression, if necessary. */ + NetExpr*expr = (*cur).second.expr; + assert(expr); + + eval_expr(expr); + + switch (expr->expr_type()) { + case IVL_VT_REAL: + if (! dynamic_cast(expr)) { + cerr << (*cur).second.expr->get_fileline() + << ": internal error: " + << "unable to evaluate real parameter value: " + << *expr << endl; + des->errors += 1; + return; + } + break; + + case IVL_VT_LOGIC: + case IVL_VT_BOOL: + if (! dynamic_cast(expr)) { + cerr << (*cur).second.expr->get_fileline() + << ": internal error: " + << "unable to evaluate parameter " + << (*cur).first + << " value: " << *expr << endl; + des->errors += 1; + return; + } + break; + + default: + cerr << (*cur).second.expr->get_fileline() + << ": internal error: " + << "unhandled expression type?" << endl; + des->errors += 1; + return; + } + + /* If the parameter has range information, then make + sure the value is set right. Note that if the + parameter doesn't have an explicit range, then it + will get the signedness from the expression itself. */ + if (range_flag) { + unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb; + wid += 1; + + NetEConst*val = dynamic_cast(expr); + assert(val); + + verinum value = val->value(); + + if (! (value.has_len() + && (value.len() == wid) + && (value.has_sign() == (*cur).second.signed_flag))) { + + verinum tmp (value, wid); + tmp.has_sign ( (*cur).second.signed_flag ); + delete val; + val = new NetEConst(tmp); + expr = val; + } + } + + // Done fiddling with the expression, save it back in the parameter. + expr->set_line(*(*cur).second.expr); + (*cur).second.expr = expr; + + NetEConst*val = dynamic_cast((*cur).second.expr); + ivl_assert(*(*cur).second.expr, (*cur).second.expr); + ivl_assert(*(*cur).second.expr, val); + + verinum value = val->value(); + + bool from_flag = (*cur).second.range == 0? true : false; + for (range_t*value_range = (*cur).second.range + ; value_range ; value_range = value_range->next) { + + // If we already know that the value is + // within a "from" range, then do not test + // any more of the from ranges. + if (from_flag && value_range->exclude_flag==false) + continue; + + if (value_range->low_expr) { + NetEConst*tmp = dynamic_cast(value_range->low_expr); + ivl_assert(*value_range->low_expr, tmp); + if (value_range->low_open_flag && value <= tmp->value()) + continue; + else if (value < tmp->value()) + continue; + } + + if (value_range->high_expr) { + NetEConst*tmp = dynamic_cast(value_range->high_expr); + ivl_assert(*value_range->high_expr, tmp); + if (value_range->high_open_flag && value >= tmp->value()) + continue; + else if (value > tmp->value()) + continue; + } + + // Within the range. If this is a "from" + // range, then set the from_flag and continue. + if (value_range->exclude_flag == false) { + from_flag = true; + continue; + } + + // OH NO! In an excluded range. signal an error. + from_flag = false; + break; + } + + // If we found no from range that contains the + // value, then report an error. + if (! from_flag) { + cerr << val->get_fileline() << ": error: " + << "Parameter value " << value + << " is out of range for parameter " << (*cur).first + << "." << endl; + des->errors += 1; + } +} + +void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur) +{ + NetExpr*expr = (*cur).second.expr; + assert(expr); + + NetECReal*res = 0; + eval_expr(expr); + + switch (expr->expr_type()) { + case IVL_VT_REAL: + if (NetECReal*tmp = dynamic_cast(expr)) { + res = tmp; + } else { + ivl_assert(*expr, 0); + } + break; + + case IVL_VT_LOGIC: + case IVL_VT_BOOL: + if (NetEConst*tmp = dynamic_cast(expr)) { + verireal val (tmp->value().as_long()); + res = new NetECReal(val); + res->set_line(*tmp); + } else { + ivl_assert(*expr, 0); + } + break; + + default: + ivl_assert(*expr, 0); + break; + } + + (*cur).second.expr = res; + double value = res->value().as_double(); + + bool from_flag = (*cur).second.range == 0? true : false; + for (range_t*value_range = (*cur).second.range + ; value_range ; value_range = value_range->next) { + + if (from_flag && value_range->exclude_flag==false) + continue; + + if (value_range->low_expr) { + double tmp; + bool flag = eval_as_double(tmp, value_range->low_expr); + ivl_assert(*value_range->low_expr, flag); + if (value_range->low_open_flag && value <= tmp) + continue; + else if (value < tmp) + continue; + } + + if (value_range->high_expr) { + double tmp; + bool flag = eval_as_double(tmp, value_range->high_expr); + ivl_assert(*value_range->high_expr, flag); + if (value_range->high_open_flag && value >= tmp) + continue; + else if (value > tmp) + continue; + } + + if (value_range->exclude_flag == false) { + from_flag = true; + continue; + } + + // All the above tests failed, so we must have tripped + // an exclude rule. + from_flag = false; + break; + } + + if (! from_flag) { + cerr << res->get_fileline() << ": error: " + << "Parameter value " << value + << " is out of range for parameter " << (*cur).first + << "." << endl; + des->errors += 1; + } +} + void NetScope::evaluate_parameters(Design*des) { NetScope*cur = sub_; @@ -257,217 +504,25 @@ void NetScope::evaluate_parameters(Design*des) // scanning code. Now the parameter expression can be fully // evaluated, or it cannot be evaluated at all. - typedef map::iterator mparm_it_t; - - for (mparm_it_t cur = parameters.begin() + for (param_ref_t cur = parameters.begin() ; cur != parameters.end() ; cur ++) { - long msb = 0; - long lsb = 0; - bool range_flag = false; - NetExpr*expr; - - /* Evaluate the msb expression, if it is present. */ - expr = (*cur).second.msb; - - if (expr) { - - NetEConst*tmp = dynamic_cast(expr); - - if (! tmp) { - - NetExpr*nexpr = expr->eval_tree(); - if (nexpr == 0) { - cerr << (*cur).second.expr->get_fileline() - << ": internal error: " - << "unable to evaluate msb expression " - << "for parameter " << (*cur).first << ": " - << *expr << endl; - des->errors += 1; - continue; - } - - assert(nexpr); - delete expr; - (*cur).second.msb = nexpr; - - tmp = dynamic_cast(nexpr); - } - - assert(tmp); - msb = tmp->value().as_long(); - range_flag = true; - } - - /* Evaluate the lsb expression, if it is present. */ - expr = (*cur).second.lsb; - if (expr) { - - NetEConst*tmp = dynamic_cast(expr); - - if (! tmp) { - - NetExpr*nexpr = expr->eval_tree(); - if (nexpr == 0) { - cerr << (*cur).second.expr->get_fileline() - << ": internal error: " - << "unable to evaluate lsb expression " - << "for parameter " << (*cur).first << ": " - << *expr << endl; - des->errors += 1; - continue; - } - - assert(nexpr); - delete expr; - (*cur).second.lsb = nexpr; - - tmp = dynamic_cast(nexpr); - } - - assert(tmp); - lsb = tmp->value().as_long(); - - assert(range_flag); - } - - - /* Evaluate the parameter expression, if necessary. */ - expr = (*cur).second.expr; - assert(expr); - - switch (expr->expr_type()) { - case IVL_VT_REAL: - if (! dynamic_cast(expr)) { - - NetExpr*nexpr = expr->eval_tree(); - if (nexpr == 0) { - cerr << (*cur).second.expr->get_fileline() - << ": internal error: " - << "unable to evaluate real parameter value: " - << *expr << endl; - des->errors += 1; - continue; - } - - assert(nexpr); - delete expr; - (*cur).second.expr = nexpr; - } + switch ((*cur).second.type) { + case IVL_VT_BOOL: + case IVL_VT_LOGIC: + evaluate_parameter_logic_(des, cur); break; - case IVL_VT_LOGIC: - case IVL_VT_BOOL: - if (! dynamic_cast(expr)) { - - // Try to evaluate the expression. - NetExpr*nexpr = expr->eval_tree(); - if (nexpr == 0) { - cerr << (*cur).second.expr->get_fileline() - << ": internal error: " - << "unable to evaluate parameter " - << (*cur).first - << " value: " << - *expr << endl; - des->errors += 1; - continue; - } - - // The evaluate worked, replace the old - // expression with this constant value. - assert(nexpr); - delete expr; - (*cur).second.expr = nexpr; - } + case IVL_VT_REAL: + evaluate_parameter_real_(des, cur); break; default: - cerr << (*cur).second.expr->get_fileline() - << ": internal error: " - << "unhandled expression type?" << endl; - des->errors += 1; - continue; - } - - /* If the parameter has range information, then make - sure the value is set right. Note that if the - parameter doesn't have an explicit range, then it - will get the signedness from the expression itself. */ - if (range_flag) { - unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb; - wid += 1; - - NetEConst*val = dynamic_cast((*cur).second.expr); - assert(val); - - verinum value = val->value(); - - if (! (value.has_len() - && (value.len() == wid) - && (value.has_sign() == (*cur).second.signed_flag))) { - - verinum tmp (value, wid); - tmp.has_sign ( (*cur).second.signed_flag ); - delete val; - val = new NetEConst(tmp); - (*cur).second.expr = val; - } - } - - if (NetEConst*val = dynamic_cast((*cur).second.expr)) { - verinum value = val->value(); - bool from_flag = (*cur).second.range == 0? true : false; - for (range_t*value_range = (*cur).second.range - ; value_range ; value_range = value_range->next) { - - // If we already know that the value is - // within a "from" range, then do not test - // any more of the from ranges. - if (from_flag && value_range->exclude_flag==false) - continue; - - if (value_range->low_expr) { - NetEConst*tmp = dynamic_cast(value_range->low_expr); - ivl_assert(*value_range->low_expr, tmp); - if (value_range->low_open_flag && value <= tmp->value()) - continue; - else if (value < tmp->value()) - continue; - } - - if (value_range->high_expr) { - NetEConst*tmp = dynamic_cast(value_range->high_expr); - ivl_assert(*value_range->high_expr, tmp); - if (value_range->high_open_flag && value >= tmp->value()) - continue; - else if (value > tmp->value()) - continue; - } - - // Within the range. If this is a "from" - // range, then set the from_flag and continue. - if (value_range->exclude_flag == false) { - from_flag = true; - continue; - } - - // OH NO! In an excluded range. signal an error. - break; - } - - // If we found no from range that contains the - // value, then report an error. - if (! from_flag) { - cerr << val->get_fileline() << ": error: " - << "Parameter value " << value - << " is out of range for parameter " << (*cur).first - << "." << endl; - des->errors += 1; - } - - } else if (NetECReal*val = dynamic_cast((*cur).second.expr)) { - // XXXX Haven't implemented this yet - ivl_assert(*val, (*cur).second.range == 0); + cerr << (*cur).second.get_fileline() << ": internal error: " + << "Unexpected expression type " << (*cur).second.type + << "." << endl; + ivl_assert((*cur).second, 0); + break; } } diff --git a/net_expr.cc b/net_expr.cc index d71ecb231..92594ea3d 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -476,7 +476,12 @@ NetEParam::NetEParam() } NetEParam::NetEParam(Design*d, NetScope*s, perm_string n) -: des_(d), scope_(s), name_(n) + : des_(d), scope_(s), reference_(scope_->find_parameter(n)) +{ +} + +NetEParam::NetEParam(Design*d, NetScope*s, ref_t ref) + : des_(d), scope_(s), reference_(ref) { } @@ -489,9 +494,14 @@ bool NetEParam::has_width() const return false; } +ivl_variable_type_t NetEParam::expr_type() const +{ + return (*reference_).second.type; +} + NetEParam* NetEParam::dup_expr() const { - NetEParam*tmp = new NetEParam(des_, scope_, name_); + NetEParam*tmp = new NetEParam(des_, scope_, reference_); tmp->set_line(*this); return tmp; } diff --git a/net_scope.cc b/net_scope.cc index cdfa67a91..59cdb1790 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -105,6 +105,7 @@ void NetScope::set_line(perm_string file, perm_string def_file, } NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr, + ivl_variable_type_t type, NetExpr*msb, NetExpr*lsb, bool signed_flag, NetScope::range_t*range_list, const LineInfo&file_line) @@ -112,6 +113,7 @@ NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr, param_expr_t&ref = parameters[key]; NetExpr* res = ref.expr; ref.expr = expr; + ref.type = type; ref.msb = msb; ref.lsb = lsb; ref.signed_flag = signed_flag; @@ -204,6 +206,20 @@ const NetExpr* NetScope::get_parameter(const char* key, return 0; } +map::iterator NetScope::find_parameter(perm_string key) +{ + map::iterator idx; + + idx = parameters.find(key); + if (idx != parameters.end()) + return idx; + + idx = localparams.find(perm_string::literal(key)); + if (idx != localparams.end()) + return idx; + + return 0; +} NetScope::TYPE NetScope::type() const { diff --git a/netlist.h b/netlist.h index 2b8c0b3c3..691311301 100644 --- a/netlist.h +++ b/netlist.h @@ -49,6 +49,7 @@ class ostream; class Design; class Link; class Nexus; +class NetEvent; class NetNet; class NetNode; class NetProc; @@ -60,6 +61,7 @@ class NetExpr; class NetESignal; class NetFuncDef; class NetRamDq; +class NetTaskDef; class NetEvTrig; class NetEvWait; @@ -578,6 +580,234 @@ class NetNet : public NetObj { vector delay_paths_; }; +/* + * This object type is used to contain a logical scope within a + * design. The scope doesn't represent any executable hardware, but is + * just a handle that netlist processors can use to grab at the design. + */ +class NetScope : public Attrib { + + public: + enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK }; + + /* Create a new scope, and attach it to the given parent. The + name is expected to have been permallocated. */ + NetScope(NetScope*up, const hname_t&name, TYPE t); + ~NetScope(); + + /* Rename the scope using the name generated by inserting as + many pad characters as required between prefix and suffix + to make the name unique in the parent scope. Return false + if a unique name couldn't be generated. */ + bool auto_name(const char* prefix, char pad, const char* suffix); + + /* Parameters exist within a scope, and these methods allow + one to manipulate the set. In these cases, the name is the + *simple* name of the parameter, the hierarchy is implicit in + the scope. The return value from set_parameter is the + previous expression, if there was one. */ + + struct range_t; + NetExpr* set_parameter(perm_string name, NetExpr*val, + ivl_variable_type_t type, + NetExpr*msb, NetExpr*lsb, bool signed_flag, + NetScope::range_t*range_list, + const LineInfo&file_line); + NetExpr* set_localparam(perm_string name, NetExpr*val, + const LineInfo&file_line); + + const NetExpr*get_parameter(const char* name, + const NetExpr*&msb, + const NetExpr*&lsb) const; + + /* These are used by defparam elaboration to replace the + expression with a new expression, without affecting the + range or signed_flag. Return false if the name does not + exist. */ + bool replace_parameter(perm_string name, NetExpr*val); + + /* These methods set or access events that live in this + scope. */ + + void add_event(NetEvent*); + void rem_event(NetEvent*); + NetEvent*find_event(perm_string name); + + + /* These methods manage signals. The add_ and rem_signal + methods are used by the NetNet objects to make themselves + available to the scope, and the find_signal method can be + used to locate signals within a scope. */ + + void add_signal(NetNet*); + void rem_signal(NetNet*); + NetNet* find_signal(perm_string name); + + /* The parent and child() methods allow users of NetScope + objects to locate nearby scopes. */ + NetScope* parent(); + NetScope* child(const hname_t&name); + const NetScope* parent() const; + const NetScope* child(const hname_t&name) const; + + TYPE type() const; + + void set_task_def(NetTaskDef*); + void set_func_def(NetFuncDef*); + void set_module_name(perm_string); + + NetTaskDef* task_def(); + NetFuncDef* func_def(); + + void set_line(perm_string file, perm_string def_file, + unsigned lineno, unsigned def_lineno); + void set_line(perm_string file, unsigned lineno); + void set_line(const LineInfo *info); + perm_string get_file() const { return file_; }; + perm_string get_def_file() const { return def_file_; }; + unsigned get_lineno() const { return lineno_; }; + unsigned get_def_lineno() const { return def_lineno_; }; + + bool in_func(); + + const NetTaskDef* task_def() const; + const NetFuncDef* func_def() const; + + /* If the scope represents a module instance, the module_name + is the name of the module itself. */ + perm_string module_name() const; + + /* Scopes have their own time units and time precision. The + unit and precision are given as power of 10, i.e., -3 is + units of milliseconds. + + If a NetScope is created with a parent scope, the new scope + will initially inherit the unit and precision of the + parent scope. */ + + void time_unit(int); + void time_precision(int); + + int time_unit() const; + int time_precision() const; + + void default_nettype(NetNet::Type); + NetNet::Type default_nettype() const; + + /* The fullname of the scope is the hierarchical name + component (which includes the name and array index) whereas + the basename is just my name. */ + perm_string basename() const; + const hname_t& fullname() const { return name_; } + + void run_defparams(class Design*); + void evaluate_parameters(class Design*); + + /* This method generates a non-hierarchical name that is + guaranteed to be unique within this scope. */ + perm_string local_symbol(); + + void dump(ostream&) const; + void emit_scope(struct target_t*tgt) const; + bool emit_defs(struct target_t*tgt) const; + + /* This method runs the functor on me. Recurse through the + children of this node as well. */ + void run_functor(Design*des, functor_t*fun); + + + /* This member is used during elaboration to pass defparam + assignments from the scope pass to the parameter evaluation + step. After that, it is not used. */ + + mapdefparams; + + public: + struct range_t { + bool exclude_flag; + // Lower bound + bool low_open_flag; + NetExpr*low_expr; + // Upper bound + bool high_open_flag; + NetExpr*high_expr; + // Link to the next range specification + struct range_t*next; + }; + + /* After everything is all set up, the code generators like + access to these things to make up the parameter lists. */ + struct param_expr_t : public LineInfo { + param_expr_t() : type(IVL_VT_NO_TYPE), range(0) { } + // Type information + ivl_variable_type_t type; + bool signed_flag; + NetExpr*msb; + NetExpr*lsb; + // range constraints + struct range_t*range; + // Expression value + NetExpr*expr; + }; + mapparameters; + maplocalparams; + + typedef map::iterator param_ref_t; + + param_ref_t find_parameter(perm_string name); + + + struct spec_val_t { + ivl_variable_type_t type; + union { + double real_val; // type == IVL_VT_REAL + long integer; // type == IVL_VT_BOOL + }; + }; + mapspecparams; + + /* Module instance arrays are collected here for access during + the multiple elaboration passes. */ + typedef svector scope_vec_t; + mapinstance_arrays; + + /* Loop generate uses this as scratch space during + elaboration. Expression evaluation can use this to match + names. */ + perm_string genvar_tmp; + long genvar_tmp_val; + + private: + void evaluate_parameter_logic_(Design*des, param_ref_t cur); + void evaluate_parameter_real_(Design*des, param_ref_t cur); + + private: + TYPE type_; + hname_t name_; + + perm_string file_; + perm_string def_file_; + unsigned lineno_; + unsigned def_lineno_; + + signed char time_unit_, time_prec_; + NetNet::Type default_nettype_; + + NetEvent *events_; + NetNet *signals_; + perm_string module_name_; + union { + NetTaskDef*task_; + NetFuncDef*func_; + }; + + NetScope*up_; + NetScope*sib_; + NetScope*sub_; + + unsigned lcounter_; +}; + /* * This class implements the LPM_ABS component. The node has a single * input, a signe expression, that it converts to the absolute @@ -3006,6 +3236,7 @@ class NetEParam : public NetExpr { virtual bool set_width(unsigned w, bool last_chance); virtual bool has_width() const; virtual void expr_scan(struct expr_scan_t*) const; + virtual ivl_variable_type_t expr_type() const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetEParam* dup_expr() const; @@ -3014,7 +3245,10 @@ class NetEParam : public NetExpr { private: Design*des_; NetScope*scope_; - perm_string name_; + typedef map::iterator ref_t; + ref_t reference_; + + NetEParam(class Design*des, NetScope*scope, ref_t ref); }; @@ -3287,223 +3521,6 @@ class NetESignal : public NetExpr { }; -/* - * This object type is used to contain a logical scope within a - * design. The scope doesn't represent any executable hardware, but is - * just a handle that netlist processors can use to grab at the design. - */ -class NetScope : public Attrib { - - public: - enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK }; - - /* Create a new scope, and attach it to the given parent. The - name is expected to have been permallocated. */ - NetScope(NetScope*up, const hname_t&name, TYPE t); - ~NetScope(); - - /* Rename the scope using the name generated by inserting as - many pad characters as required between prefix and suffix - to make the name unique in the parent scope. Return false - if a unique name couldn't be generated. */ - bool auto_name(const char* prefix, char pad, const char* suffix); - - /* Parameters exist within a scope, and these methods allow - one to manipulate the set. In these cases, the name is the - *simple* name of the parameter, the hierarchy is implicit in - the scope. The return value from set_parameter is the - previous expression, if there was one. */ - - struct range_t; - NetExpr* set_parameter(perm_string name, NetExpr*val, - NetExpr*msb, NetExpr*lsb, bool signed_flag, - NetScope::range_t*range_list, - const LineInfo&file_line); - NetExpr* set_localparam(perm_string name, NetExpr*val, - const LineInfo&file_line); - - const NetExpr*get_parameter(const char* name, - const NetExpr*&msb, - const NetExpr*&lsb) const; - - /* These are used by defparam elaboration to replace the - expression with a new expression, without affecting the - range or signed_flag. Return false if the name does not - exist. */ - bool replace_parameter(perm_string name, NetExpr*val); - - /* These methods set or access events that live in this - scope. */ - - void add_event(NetEvent*); - void rem_event(NetEvent*); - NetEvent*find_event(perm_string name); - - - /* These methods manage signals. The add_ and rem_signal - methods are used by the NetNet objects to make themselves - available to the scope, and the find_signal method can be - used to locate signals within a scope. */ - - void add_signal(NetNet*); - void rem_signal(NetNet*); - NetNet* find_signal(perm_string name); - - /* The parent and child() methods allow users of NetScope - objects to locate nearby scopes. */ - NetScope* parent(); - NetScope* child(const hname_t&name); - const NetScope* parent() const; - const NetScope* child(const hname_t&name) const; - - TYPE type() const; - - void set_task_def(NetTaskDef*); - void set_func_def(NetFuncDef*); - void set_module_name(perm_string); - - NetTaskDef* task_def(); - NetFuncDef* func_def(); - - void set_line(perm_string file, perm_string def_file, - unsigned lineno, unsigned def_lineno); - void set_line(perm_string file, unsigned lineno); - void set_line(const LineInfo *info); - perm_string get_file() const { return file_; }; - perm_string get_def_file() const { return def_file_; }; - unsigned get_lineno() const { return lineno_; }; - unsigned get_def_lineno() const { return def_lineno_; }; - - bool in_func(); - - const NetTaskDef* task_def() const; - const NetFuncDef* func_def() const; - - /* If the scope represents a module instance, the module_name - is the name of the module itself. */ - perm_string module_name() const; - - /* Scopes have their own time units and time precision. The - unit and precision are given as power of 10, i.e., -3 is - units of milliseconds. - - If a NetScope is created with a parent scope, the new scope - will initially inherit the unit and precision of the - parent scope. */ - - void time_unit(int); - void time_precision(int); - - int time_unit() const; - int time_precision() const; - - void default_nettype(NetNet::Type); - NetNet::Type default_nettype() const; - - /* The fullname of the scope is the hierarchical name - component (which includes the name and array index) whereas - the basename is just my name. */ - perm_string basename() const; - const hname_t& fullname() const { return name_; } - - void run_defparams(class Design*); - void evaluate_parameters(class Design*); - - /* This method generates a non-hierarchical name that is - guaranteed to be unique within this scope. */ - perm_string local_symbol(); - - void dump(ostream&) const; - void emit_scope(struct target_t*tgt) const; - bool emit_defs(struct target_t*tgt) const; - - /* This method runs the functor on me. Recurse through the - children of this node as well. */ - void run_functor(Design*des, functor_t*fun); - - - /* This member is used during elaboration to pass defparam - assignments from the scope pass to the parameter evaluation - step. After that, it is not used. */ - - mapdefparams; - - public: - struct range_t { - bool exclude_flag; - // Lower bound - bool low_open_flag; - NetExpr*low_expr; - // Upper bound - bool high_open_flag; - NetExpr*high_expr; - // Link to the next range specification - struct range_t*next; - }; - - /* After everything is all set up, the code generators like - access to these things to make up the parameter lists. */ - struct param_expr_t : public LineInfo { - param_expr_t() : range(0) { } - // Type information - bool signed_flag; - NetExpr*msb; - NetExpr*lsb; - // range constraints - struct range_t*range; - // Expression value - NetExpr*expr; - }; - mapparameters; - maplocalparams; - - struct spec_val_t { - ivl_variable_type_t type; - union { - double real_val; // type == IVL_VT_REAL - long integer; // type == IVL_VT_BOOL - }; - }; - mapspecparams; - - /* Module instance arrays are collected here for access during - the multiple elaboration passes. */ - typedef svector scope_vec_t; - mapinstance_arrays; - - /* Loop generate uses this as scratch space during - elaboration. Expression evaluation can use this to match - names. */ - perm_string genvar_tmp; - long genvar_tmp_val; - - private: - TYPE type_; - hname_t name_; - - perm_string file_; - perm_string def_file_; - unsigned lineno_; - unsigned def_lineno_; - - signed char time_unit_, time_prec_; - NetNet::Type default_nettype_; - - NetEvent *events_; - NetNet *signals_; - perm_string module_name_; - union { - NetTaskDef*task_; - NetFuncDef*func_; - }; - - NetScope*up_; - NetScope*sib_; - NetScope*sub_; - - unsigned lcounter_; -}; - /* * This class contains an entire design. It includes processes and a * netlist, and can be passed around from function to function. diff --git a/netmisc.cc b/netmisc.cc index 258858a9f..ac69d6885 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -182,6 +182,21 @@ bool eval_as_long(long&value, NetExpr*expr) return false; } +bool eval_as_double(double&value, NetExpr*expr) +{ + if (NetEConst*tmp = dynamic_cast(expr) ) { + value = tmp->value().as_long(); + return true; + } + + if (NetECReal*rtmp = dynamic_cast(expr)) { + value = rtmp->value().as_double(); + return true; + } + + return false; +} + std::list eval_scope_path(Design*des, NetScope*scope, const pform_name_t&path) { diff --git a/netmisc.h b/netmisc.h index 1633396c2..439e86422 100644 --- a/netmisc.h +++ b/netmisc.h @@ -138,6 +138,7 @@ void eval_expr(NetExpr*&expr, int prune_width =-1); * down to a constant) then return false and leave value unchanged. */ bool eval_as_long(long&value, NetExpr*expr); +bool eval_as_double(double&value, NetExpr*expr); extern std::list eval_scope_path(Design*des, NetScope*scope, const pform_name_t&path); diff --git a/parse.y b/parse.y index 0ec6c273b..648a9c657 100644 --- a/parse.y +++ b/parse.y @@ -35,8 +35,9 @@ class PSpecPath; extern void lex_start_table(); extern void lex_end_table(); -static svector* active_range = 0; -static bool active_signed = false; +static svector* param_active_range = 0; +static bool param_active_signed = false; +static ivl_variable_type_t param_active_type = IVL_VT_LOGIC; /* Port declaration lists use this structure for context. */ static struct { @@ -2356,23 +2357,48 @@ var_type generates a type (optional) and a list of assignments. */ parameter_assign_decl - : parameter_assign_list - | range { active_range = $1; active_signed = false; } - parameter_assign_list - { active_range = 0; - active_signed = false; - } - | K_signed range { active_range = $2; active_signed = true; } - parameter_assign_list - { active_range = 0; - active_signed = false; - } - | K_integer { active_range = 0; active_signed = true; } - parameter_assign_list - { active_range = 0; - active_signed = false; - } - ; + : parameter_assign_list + | range + { param_active_range = $1; + param_active_signed = false; + param_active_type = IVL_VT_LOGIC; + } + parameter_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_LOGIC; + } + | K_signed range + { param_active_range = $2; + param_active_signed = true; + param_active_type = IVL_VT_LOGIC; + } + parameter_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_LOGIC; + } + | K_integer + { param_active_range = 0; + param_active_signed = true; + param_active_type = IVL_VT_LOGIC; + } + parameter_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_LOGIC; + } + | K_real + { param_active_range = 0; + param_active_signed = true; + param_active_type = IVL_VT_REAL; + } + parameter_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_LOGIC; + } + ; parameter_assign_list : parameter_assign @@ -2382,8 +2408,8 @@ parameter_assign_list parameter_assign : IDENTIFIER '=' expression parameter_value_ranges_opt { PExpr*tmp = $3; - pform_set_parameter(@1, lex_strings.make($1), - active_signed, active_range, tmp, $4); + pform_set_parameter(@1, lex_strings.make($1), param_active_type, + param_active_signed, param_active_range, tmp, $4); delete[]$1; } ; @@ -2424,40 +2450,59 @@ from_exclude : K_from { $$ = false; } | K_exclude { $$ = true; } ; behave differently when someone tries to override them. */ localparam_assign - : IDENTIFIER '=' expression - { PExpr*tmp = $3; - if (!pform_expression_is_constant(tmp)) { - yyerror(@3, "error: parameter value " - "must be constant."); - delete tmp; - tmp = 0; - } else { - pform_set_localparam(@1, lex_strings.make($1), - active_signed, - active_range, tmp); - } - delete[]$1; - } - ; + : IDENTIFIER '=' expression + { PExpr*tmp = $3; + pform_set_localparam(@1, lex_strings.make($1), + param_active_type, + param_active_signed, + param_active_range, tmp); + delete[]$1; + } + ; localparam_assign_decl - : localparam_assign_list - | range { active_range = $1; active_signed = false; } - localparam_assign_list - { active_range = 0; - active_signed = false; - } - | K_signed range { active_range = $2; active_signed = true; } - localparam_assign_list - { active_range = 0; - active_signed = false; - } - | K_integer { active_range = 0; active_signed = true; } - localparam_assign_list - { active_range = 0; - active_signed = false; - } - ; + : localparam_assign_list + | range + { param_active_range = $1; + param_active_signed = false; + param_active_type = IVL_VT_LOGIC; + } + localparam_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_NO_TYPE; + } + | K_signed range + { param_active_range = $2; + param_active_signed = true; + param_active_type = IVL_VT_LOGIC; + } + localparam_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_NO_TYPE; + } + | K_integer + { param_active_range = 0; + param_active_signed = true; + param_active_type = IVL_VT_LOGIC; + } + localparam_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_NO_TYPE; + } + | K_real + { param_active_range = 0; + param_active_signed = true; + param_active_type = IVL_VT_REAL; + } + localparam_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_NO_TYPE; + } + ; localparam_assign_list : localparam_assign diff --git a/pform.cc b/pform.cc index a800b9f50..4aa94080d 100644 --- a/pform.cc +++ b/pform.cc @@ -1654,8 +1654,8 @@ Module::range_t* pform_parameter_value_range(bool exclude_flag, } void pform_set_parameter(const struct vlltype&loc, - perm_string name, bool signed_flag, - svector*range, PExpr*expr, + perm_string name, ivl_variable_type_t type, + bool signed_flag, svector*range, PExpr*expr, Module::range_t*value_range) { assert(expr); @@ -1664,6 +1664,7 @@ void pform_set_parameter(const struct vlltype&loc, parm.expr = expr; + parm.type = type; if (range) { assert(range->count() == 2); assert((*range)[0]); @@ -1681,8 +1682,8 @@ void pform_set_parameter(const struct vlltype&loc, } void pform_set_localparam(const struct vlltype&loc, - perm_string name, bool signed_flag, - svector*range, PExpr*expr) + perm_string name, ivl_variable_type_t type, + bool signed_flag, svector*range, PExpr*expr) { assert(expr); Module::param_expr_t&parm = pform_cur_module->localparams[name]; @@ -1690,6 +1691,7 @@ void pform_set_localparam(const struct vlltype&loc, parm.expr = expr; + parm.type = type; if (range) { assert(range->count() == 2); assert((*range)[0]); diff --git a/pform.h b/pform.h index f5b18c344..a94be9f96 100644 --- a/pform.h +++ b/pform.h @@ -272,11 +272,13 @@ extern Module::range_t* pform_parameter_value_range(bool exclude_flag, extern void pform_set_parameter(const struct vlltype&loc, perm_string name, + ivl_variable_type_t type, bool signed_flag, svector*range, PExpr*expr, Module::range_t*value_range); extern void pform_set_localparam(const struct vlltype&loc, perm_string name, + ivl_variable_type_t type, bool signed_flag, svector*range, PExpr*expr); diff --git a/pform_dump.cc b/pform_dump.cc index 8728d280e..c3e709ad4 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -994,7 +994,7 @@ void Module::dump(ostream&out) const typedef map::const_iterator parm_hiter_t; for (parm_iter_t cur = parameters.begin() ; cur != parameters.end() ; cur ++) { - out << " parameter "; + out << " parameter " << (*cur).second.type << " "; if ((*cur).second.signed_flag) out << "signed "; if ((*cur).second.msb)