From c76e88cad5ffee21aedb4100ff36cb1c6e5dd473 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 17 May 2008 16:25:58 -0700 Subject: [PATCH] Add support for explicit parameter types, including real. Before this, the types of parameters were always logic, only the width and signed-ness could be controlled. A parameter may take on implicit real values if the expression were real. With this patch, the type for the parameter can be explicitly set to logic or real. This also means that the parameter real valued expressions need to be more crefully treated, possibly with casting integral expressions to real values, or real expressions to integral values. --- Module.h | 6 +- design_dump.cc | 6 +- elab_scope.cc | 12 +- eval_tree.cc | 34 ++-- net_design.cc | 463 +++++++++++++++++++++++++++---------------------- net_expr.cc | 14 +- net_scope.cc | 16 ++ netlist.h | 453 ++++++++++++++++++++++++----------------------- netmisc.cc | 15 ++ netmisc.h | 1 + parse.y | 151 ++++++++++------ pform.cc | 10 +- pform.h | 2 + pform_dump.cc | 2 +- 14 files changed, 675 insertions(+), 510 deletions(-) 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)