diff --git a/PExpr.h b/PExpr.h index 337305e6b..774ed62a5 100644 --- a/PExpr.h +++ b/PExpr.h @@ -45,6 +45,11 @@ class PExpr : public LineInfo { public: enum width_mode_t { SIZED, EXPAND, LOSSLESS, UNSIZED }; + // Flag values that can be passed to elaborate_expr. + static const unsigned NO_FLAGS = 0x0; + static const unsigned NEED_CONST = 0x1; + static const unsigned SYS_TASK_ARG = 0x2; + PExpr(); virtual ~PExpr(); @@ -122,7 +127,7 @@ class PExpr : public LineInfo { // be incomplete. virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; // This method elaborates the expression as gates, but // restricted for use as l-values of continuous assignments. @@ -195,7 +200,7 @@ class PEConcat : public PExpr { virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope, bool is_force) const; @@ -261,7 +266,7 @@ class PEFNumber : public PExpr { width_mode_t&mode); virtual NetExpr*elaborate_expr(Design*des, NetScope*, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; virtual void dump(ostream&) const; @@ -301,7 +306,7 @@ class PEIdent : public PExpr { virtual NetExpr*elaborate_expr(Design*des, NetScope*, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; // Elaborate the PEIdent as a port to a module. This method // only applies to Ident expressions. @@ -330,7 +335,7 @@ class PEIdent : public PExpr { // invalid bits (xz) in either expression, then the defined // flag is set to *false*. bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb, bool&defined) const; - NetExpr* calculate_up_do_base_(Design*, NetScope*) const; + NetExpr* calculate_up_do_base_(Design*, NetScope*, bool need_const) const; bool calculate_param_range_(Design*, NetScope*, const NetExpr*msb_ex, long&msb, const NetExpr*lsb_ex, long&lsb, @@ -352,7 +357,8 @@ class PEIdent : public PExpr { NetScope*found, const NetExpr*par_msb, const NetExpr*par_lsb, - unsigned expr_wid) const; + unsigned expr_wid, + unsigned flags) const; NetExpr*elaborate_expr_param_part_(Design*des, NetScope*scope, const NetExpr*par, @@ -365,25 +371,27 @@ class PEIdent : public PExpr { const NetExpr*par, NetScope*found, const NetExpr*par_msb, - const NetExpr*par_lsb) const; + const NetExpr*par_lsb, + bool need_const) const; NetExpr*elaborate_expr_param_idx_do_(Design*des, NetScope*scope, const NetExpr*par, NetScope*found, const NetExpr*par_msb, - const NetExpr*par_lsb) const; + const NetExpr*par_lsb, + bool need_const) const; NetExpr*elaborate_expr_net(Design*des, NetScope*scope, NetNet*net, NetScope*found, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; NetExpr*elaborate_expr_net_word_(Design*des, NetScope*scope, NetNet*net, NetScope*found, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; NetExpr*elaborate_expr_net_part_(Design*des, NetScope*scope, NetESignal*net, @@ -392,15 +400,18 @@ class PEIdent : public PExpr { NetExpr*elaborate_expr_net_idx_up_(Design*des, NetScope*scope, NetESignal*net, - NetScope*found) const; + NetScope*found, + bool need_const) const; NetExpr*elaborate_expr_net_idx_do_(Design*des, NetScope*scope, NetESignal*net, - NetScope*found) const; + NetScope*found, + bool need_const) const; NetExpr*elaborate_expr_net_bit_(Design*des, NetScope*scope, NetESignal*net, - NetScope*found) const; + NetScope*found, + bool need_const) const; private: NetNet* elaborate_lnet_common_(Design*des, NetScope*scope, @@ -423,7 +434,7 @@ class PENumber : public PExpr { width_mode_t&mode); virtual NetEConst*elaborate_expr(Design*des, NetScope*, - unsigned expr_wid, bool) const; + unsigned expr_wid, unsigned) const; virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope, bool is_force) const; @@ -456,7 +467,7 @@ class PEString : public PExpr { width_mode_t&mode); virtual NetEConst*elaborate_expr(Design*des, NetScope*, - unsigned expr_wid, bool) const; + unsigned expr_wid, unsigned) const; verinum* eval_const(Design*, NetScope*) const; private: @@ -480,7 +491,7 @@ class PEUnary : public PExpr { virtual NetExpr*elaborate_expr(Design*des, NetScope*, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; virtual verinum* eval_const(Design*des, NetScope*sc) const; private: @@ -508,7 +519,7 @@ class PEBinary : public PExpr { virtual NetExpr*elaborate_expr(Design*des, NetScope*, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; virtual verinum* eval_const(Design*des, NetScope*sc) const; protected: @@ -546,7 +557,7 @@ class PEBComp : public PEBinary { width_mode_t&mode); NetExpr* elaborate_expr(Design*des, NetScope*scope, - unsigned expr_wid, bool sys_task_arg) const; + unsigned expr_wid, unsigned flags) const; private: unsigned l_width_; @@ -566,7 +577,7 @@ class PEBLogic : public PEBinary { width_mode_t&mode); NetExpr* elaborate_expr(Design*des, NetScope*scope, - unsigned expr_wid, bool sys_task_arg) const; + unsigned expr_wid, unsigned flags) const; }; /* @@ -589,7 +600,7 @@ class PEBLeftWidth : public PEBinary { virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; }; class PEBPower : public PEBLeftWidth { @@ -633,12 +644,13 @@ class PETernary : public PExpr { virtual NetExpr*elaborate_expr(Design*des, NetScope*, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; virtual verinum* eval_const(Design*des, NetScope*sc) const; private: NetExpr* elab_and_eval_alternative_(Design*des, NetScope*scope, - PExpr*expr, unsigned expr_wid) const; + PExpr*expr, unsigned expr_wid, + unsigned flags) const; private: PExpr*expr_; @@ -672,7 +684,7 @@ class PECallFunction : public PExpr { virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; virtual unsigned test_width(Design*des, NetScope*scope, width_mode_t&mode); @@ -686,7 +698,8 @@ class PECallFunction : public PExpr { NetExpr* cast_to_width_(NetExpr*expr, unsigned wid) const; NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, - unsigned expr_wid) const; + unsigned expr_wid, + unsigned flags) const; NetExpr* elaborate_access_func_(Design*des, NetScope*scope, ivl_nature_t, unsigned expr_wid) const; unsigned test_width_sfunc_(Design*des, NetScope*scope, @@ -705,7 +718,7 @@ class PEVoid : public PExpr { virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, - bool sys_task_arg) const; + unsigned flags) const; }; #endif diff --git a/elab_expr.cc b/elab_expr.cc index 24a61469b..7b8a76594 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -82,7 +82,7 @@ static NetBranch* find_existing_implicit_branch(NetNet*sig, NetNet*gnd) NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_variable_type_t lv_type, unsigned lv_width, - PExpr*expr) + PExpr*expr, bool need_const) { int context_wid = -1; switch (lv_type) { @@ -99,7 +99,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, break; } - return elab_and_eval(des, scope, expr, context_wid); + return elab_and_eval(des, scope, expr, context_wid, need_const); } /* @@ -127,7 +127,7 @@ unsigned PExpr::test_width(Design*des, NetScope*, width_mode_t&) return 1; } -NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, unsigned, bool) const +NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, unsigned, unsigned) const { cerr << get_fileline() << ": internal error: I do not know how to" << " elaborate this expression. " << endl; @@ -224,8 +224,10 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode) * types. */ NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope, - unsigned expr_wid, bool) const + unsigned expr_wid, unsigned flags) const { + flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag + ivl_assert(*this, left_); ivl_assert(*this, right_); @@ -249,8 +251,8 @@ NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope, left_->cast_signed(signed_flag_); } - NetExpr*lp = left_->elaborate_expr(des, scope, l_width, false); - NetExpr*rp = right_->elaborate_expr(des, scope, r_width, false); + NetExpr*lp = left_->elaborate_expr(des, scope, l_width, flags); + NetExpr*rp = right_->elaborate_expr(des, scope, r_width, flags); if ((lp == 0) || (rp == 0)) { delete lp; delete rp; @@ -505,8 +507,10 @@ unsigned PEBComp::test_width(Design*des, NetScope*scope, width_mode_t&) } NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, - unsigned expr_wid, bool) const + unsigned expr_wid, unsigned flags) const { + flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag + ivl_assert(*this, left_); ivl_assert(*this, right_); @@ -517,8 +521,8 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, if (type_is_vectorable(right_->expr_type()) && !right_->has_sign()) left_->cast_signed(false); - NetExpr*lp = left_->elaborate_expr(des, scope, l_width_, false); - NetExpr*rp = right_->elaborate_expr(des, scope, r_width_, false); + NetExpr*lp = left_->elaborate_expr(des, scope, l_width_, flags); + NetExpr*rp = right_->elaborate_expr(des, scope, r_width_, flags); if ((lp == 0) || (rp == 0)) { delete lp; delete rp; @@ -569,13 +573,14 @@ unsigned PEBLogic::test_width(Design*, NetScope*, width_mode_t&) } NetExpr*PEBLogic::elaborate_expr(Design*des, NetScope*scope, - unsigned expr_wid, bool) const + unsigned expr_wid, unsigned flags) const { ivl_assert(*this, left_); ivl_assert(*this, right_); - NetExpr*lp = elab_and_eval(des, scope, left_, -1); - NetExpr*rp = elab_and_eval(des, scope, right_, -1); + bool need_const = NEED_CONST & flags; + NetExpr*lp = elab_and_eval(des, scope, left_, -1, need_const); + NetExpr*rp = elab_and_eval(des, scope, right_, -1, need_const); if ((lp == 0) || (rp == 0)) { delete lp; delete rp; @@ -626,7 +631,7 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode) // If the right operand is constant, we can use the // actual value. - NetExpr*rp = right_->elaborate_expr(des, scope, r_width, false); + NetExpr*rp = right_->elaborate_expr(des, scope, r_width, NO_FLAGS); if (rp) { eval_expr(rp, r_width); } else { @@ -707,8 +712,10 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode) } NetExpr*PEBLeftWidth::elaborate_expr(Design*des, NetScope*scope, - unsigned expr_wid, bool) const + unsigned expr_wid, unsigned flags) const { + flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag + ivl_assert(*this, left_); // The left operand is always context determined, so propagate @@ -717,8 +724,8 @@ NetExpr*PEBLeftWidth::elaborate_expr(Design*des, NetScope*scope, unsigned r_width = right_->expr_width(); - NetExpr*lp = left_->elaborate_expr(des, scope, expr_wid, false); - NetExpr*rp = right_->elaborate_expr(des, scope, r_width, false); + NetExpr*lp = left_->elaborate_expr(des, scope, expr_wid, flags); + NetExpr*rp = right_->elaborate_expr(des, scope, r_width, flags); if (lp == 0 || rp == 0) { delete lp; delete rp; @@ -1074,7 +1081,8 @@ NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const * known function names. */ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, - unsigned expr_wid) const + unsigned expr_wid, + unsigned flags) const { perm_string name = peek_tail_name(path_); @@ -1090,7 +1098,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, } PExpr*expr = parms_[0]; - NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, true); + NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, flags); return cast_to_width_(sub, expr_wid); } @@ -1162,11 +1170,14 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, expression as much as possible, and use the reduced expression if one is created. */ + bool need_const = NEED_CONST & flags; + unsigned missing_parms = 0; for (unsigned idx = 0 ; idx < nparms ; idx += 1) { PExpr*expr = parms_[idx]; if (expr) { - NetExpr*tmp = elab_sys_task_arg(des, scope, name, idx, expr); + NetExpr*tmp = elab_sys_task_arg(des, scope, name, idx, + expr, need_const); fun->parm(idx, tmp); } else { @@ -1250,10 +1261,12 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope, } NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, - unsigned expr_wid, bool) const + unsigned expr_wid, unsigned flags) const { + flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag + if (peek_tail_name(path_)[0] == '$') - return elaborate_sfunc_(des, scope, expr_wid); + return elaborate_sfunc_(des, scope, expr_wid, flags); NetFuncDef*def = des->find_function(scope, path_); if (def == 0) { @@ -1268,7 +1281,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, // We do not currently support constant user function and // this is where things fail because of that, though we // don't know for sure so we need to display both messages. - if (need_constant_expr || is_param_expr) { + if (NEED_CONST & flags) { cerr << get_fileline() << ": sorry: constant user " "functions are not currently supported: " << path_ << "()." << endl << " or" << endl; @@ -1297,6 +1310,8 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, of the function being called. The scope of the called function is elaborated when the definition is elaborated. */ + bool need_const = NEED_CONST & flags; + unsigned missing_parms = 0; for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) { PExpr*tmp = parms_[idx]; @@ -1304,7 +1319,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, parms[idx] = elaborate_rval_expr(des, scope, def->port(idx)->data_type(), (unsigned)def->port(idx)->vector_width(), - tmp); + tmp, need_const); if (NetEEvent*evt = dynamic_cast (parms[idx])) { cerr << evt->get_fileline() << ": error: An event '" << evt->event()->name() << "' can not be a user " @@ -1372,9 +1387,7 @@ unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&) /* If there is a repeat expression, then evaluate the constant value and set the repeat count. */ if (repeat_ && (scope != tested_scope_)) { - need_constant_expr = true; - NetExpr*tmp = elab_and_eval(des, scope, repeat_, -1); - need_constant_expr = false; + NetExpr*tmp = elab_and_eval(des, scope, repeat_, -1, true); if (tmp == 0) return 0; if (tmp->expr_type() == IVL_VT_REAL) { @@ -1426,8 +1439,10 @@ unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&) static int concat_depth = 0; NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, - unsigned expr_wid, bool) const + unsigned expr_wid, unsigned flags) const { + flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag + concat_depth += 1; if (debug_elaborate) { @@ -1459,7 +1474,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, assert(parms_[idx]); unsigned wid = parms_[idx]->expr_width(); - NetExpr*ex = parms_[idx]->elaborate_expr(des, scope, wid, false); + NetExpr*ex = parms_[idx]->elaborate_expr(des, scope, wid, flags); if (ex == 0) continue; ex->set_line(*parms_[idx]); @@ -1542,7 +1557,7 @@ unsigned PEFNumber::test_width(Design*, NetScope*, width_mode_t&) return expr_width_; } -NetExpr* PEFNumber::elaborate_expr(Design*, NetScope*, unsigned, bool) const +NetExpr* PEFNumber::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const { NetECReal*tmp = new NetECReal(*value_); tmp->set_line(*this); @@ -1569,9 +1584,7 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope, two bit select expressions, and both must be constant. Evaluate them and pass the results back to the caller. */ - need_constant_expr = true; - NetExpr*lsb_ex = elab_and_eval(des, scope, index_tail.lsb, -1); - need_constant_expr = false; + NetExpr*lsb_ex = elab_and_eval(des, scope, index_tail.lsb, -1, true); NetEConst*lsb_c = dynamic_cast(lsb_ex); if (lsb_c == 0) { cerr << index_tail.lsb->get_fileline() << ": error: " @@ -1589,9 +1602,7 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope, lsb = lsb_c->value().as_long(); } - need_constant_expr = true; - NetExpr*msb_ex = elab_and_eval(des, scope, index_tail.msb, -1); - need_constant_expr = false; + NetExpr*msb_ex = elab_and_eval(des, scope, index_tail.msb, -1, true); NetEConst*msb_c = dynamic_cast(msb_ex); if (msb_c == 0) { cerr << index_tail.msb->get_fileline() << ": error: " @@ -1628,9 +1639,7 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope, /* Calculate the width expression (in the lsb_ position) first. If the expression is not constant, error but guess 1 so we can keep going and find more errors. */ - need_constant_expr = true; - NetExpr*wid_ex = elab_and_eval(des, scope, index_tail.lsb, -1); - need_constant_expr = false; + NetExpr*wid_ex = elab_and_eval(des, scope, index_tail.lsb, -1, true); NetEConst*wid_c = dynamic_cast(wid_ex); if (wid_c == 0) { @@ -1651,7 +1660,8 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope, * When we know that this is an indexed part select (up or down) this * method calculates the up/down base, as far at it can be calculated. */ -NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope) const +NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope, + bool need_const) const { const name_component_t&name_tail = path_.back(); ivl_assert(*this, !name_tail.index.empty()); @@ -1660,7 +1670,7 @@ NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope) const ivl_assert(*this, index_tail.lsb != 0); ivl_assert(*this, index_tail.msb != 0); - NetExpr*tmp = elab_and_eval(des, scope, index_tail.msb, -1); + NetExpr*tmp = elab_and_eval(des, scope, index_tail.msb, -1, need_const); return tmp; } @@ -1831,7 +1841,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) * The signal name may be escaped, but that affects nothing here. */ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, - unsigned expr_wid, bool sys_task_arg) const + unsigned expr_wid, unsigned flags) const { assert(scope); @@ -1841,10 +1851,10 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, const NetExpr*ex1, *ex2; - if (is_param_expr && path_.size() > 1) { - cerr << get_fileline() << ": error: parameter r-value expression " - "does not support hierarchical references `" << path_ - << "`." << endl; + if ((NEED_CONST & flags) && (path_.size() > 1)) { + cerr << get_fileline() << ": error: A hierarchical reference ('" + << path_ << "') is not allowed in a constant expression." + << endl; des->errors += 1; return 0; } @@ -1857,7 +1867,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, // the parameter value. if (par != 0) { NetExpr*tmp = elaborate_expr_param_(des, scope, par, found_in, - ex1, ex2, expr_wid); + ex1, ex2, expr_wid, flags); if (!tmp) return 0; @@ -1867,20 +1877,19 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, return tmp; } - // If this is a parameter expression, no other identifiers are valid. - if (is_param_expr) { - cerr << get_fileline() << ": error: identifier `" - << path_ << "` is not a parameter in " - << scope_path(scope) << "." << endl; - des->errors += 1; - return 0; - } - // If the identifier names a signal (a register or wire) // then create a NetESignal node to handle it. if (net != 0) { + if (NEED_CONST & flags) { + cerr << get_fileline() << ": error: A reference to a wire " + "or register ('" << path_ << "') is not allowed in " + "a constant expression." << endl; + des->errors += 1; + return 0; + } + NetExpr*tmp = elaborate_expr_net(des, scope, net, found_in, - expr_wid, sys_task_arg); + expr_wid, flags); if (!tmp) return 0; @@ -1890,9 +1899,17 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, return tmp; } - // If the identifier is a named event. - // is a variable reference. + // If the identifier is a named event + // then create a NetEEvent node to handle it. if (eve != 0) { + if (NEED_CONST & flags) { + cerr << get_fileline() << ": error: A reference to a named " + "event ('" << path_ << "') is not allowed in a " + "constant expression." << endl; + des->errors += 1; + return 0; + } + NetEEvent*tmp = new NetEEvent(eve); tmp->set_line(*this); return tmp; @@ -1987,7 +2004,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, } NetExpr*expr = elaborate_expr_net(des, scope, net, found_in, - expr_wid, false); + expr_wid, NO_FLAGS); NetESFunc*sys_expr = 0; if (method_name == "name") { @@ -2007,7 +2024,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, << " attached to " << use_path << "." << endl; des->errors += 1; return elaborate_expr_net(des, scope, net, found_in, - expr_wid, false); + expr_wid, NO_FLAGS); } sys_expr->set_line(*this); @@ -2023,10 +2040,12 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, // are not scopes. If this is not a system task argument, then // it cannot be a scope name, so give up. - if (! sys_task_arg) { + if ( !(SYS_TASK_ARG & flags) ) { // I cannot interpret this identifier. Error message. - cerr << get_fileline() << ": error: Unable to bind wire/reg/memory " - "`" << path_ << "' in `" << scope_path(scope) << "'"<< endl; + cerr << get_fileline() << ": error: Unable to bind " + << (NEED_CONST & flags ? "parameter" : "wire/reg/memory") + << " `" << path_ << "' in `" << scope_path(scope) << "'" + << endl; des->errors += 1; return 0; } @@ -2063,7 +2082,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, << nsc->basename() << " path=" << path_ << endl; - if (! sys_task_arg) { + if ( !(SYS_TASK_ARG & flags) ) { cerr << get_fileline() << ": error: Scope name " << nsc->basename() << " not allowed here." << endl; des->errors += 1; @@ -2248,7 +2267,8 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, const NetExpr*par, NetScope*, const NetExpr*par_msb, - const NetExpr*par_lsb) const + const NetExpr*par_lsb, + bool need_const) const { const NetEConst*par_ex = dynamic_cast (par); ivl_assert(*this, par_ex); @@ -2258,7 +2278,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, par_lsb, par_lsv, par_ex->value().len())) return 0; - NetExpr*base = calculate_up_do_base_(des, scope); + NetExpr*base = calculate_up_do_base_(des, scope, need_const); if (base == 0) return 0; unsigned long wid = 0; @@ -2327,7 +2347,8 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, const NetExpr*par, NetScope*, const NetExpr*par_msb, - const NetExpr*par_lsb) const + const NetExpr*par_lsb, + bool need_const) const { const NetEConst*par_ex = dynamic_cast (par); ivl_assert(*this, par_ex); @@ -2337,7 +2358,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, par_lsb, par_lsv, par_ex->value().len())) return 0; - NetExpr*base = calculate_up_do_base_(des, scope); + NetExpr*base = calculate_up_do_base_(des, scope, need_const); if (base == 0) return 0; unsigned long wid = 0; @@ -2414,8 +2435,10 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, - unsigned expr_wid) const + unsigned expr_wid, unsigned flags) const { + bool need_const = NEED_CONST & flags; + const name_component_t&name_tail = path_.back(); index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; if (!name_tail.index.empty()) @@ -2440,11 +2463,11 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, if (use_sel == index_component_t::SEL_IDX_UP) return elaborate_expr_param_idx_up_(des, scope, par, found_in, - par_msb, par_lsb); + par_msb, par_lsb, need_const); if (use_sel == index_component_t::SEL_IDX_DO) return elaborate_expr_param_idx_do_(des, scope, par, found_in, - par_msb, par_lsb); + par_msb, par_lsb, need_const); // NOTE TO SELF (continued): The code below should be // rewritten in the above format, as I get to it. @@ -2469,7 +2492,8 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, /* Handle the case where a parameter has a bit select attached to it. Generate a NetESelect object to select the bit as desired. */ - NetExpr*mtmp = elab_and_eval(des, scope, index_tail.msb, -1); + NetExpr*mtmp = elab_and_eval(des, scope, index_tail.msb, -1, + need_const); /* Let's first try to get constant values for both the parameter and the bit select. If they are @@ -2622,11 +2646,13 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, NetNet*net, NetScope*found_in, unsigned expr_wid, - bool sys_task_arg) const + unsigned flags) const { + bool need_const = NEED_CONST & flags; + const name_component_t&name_tail = path_.back(); - if (name_tail.index.empty() && !sys_task_arg) { + if (name_tail.index.empty() && !(SYS_TASK_ARG & flags)) { cerr << get_fileline() << ": error: Array " << path() << " Needs an array index here." << endl; des->errors += 1; @@ -2647,10 +2673,12 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, ivl_assert(*this, !index_front.lsb); } - NetExpr*word_index = index_front.sel == index_component_t::SEL_NONE - ? 0 - : elab_and_eval(des, scope, index_front.msb, -1); - if (word_index == 0 && !sys_task_arg) + NetExpr*word_index = 0; + if (index_front.sel != index_component_t::SEL_NONE) + word_index = elab_and_eval(des, scope, index_front.msb, -1, + need_const); + + if (word_index == 0 && !(SYS_TASK_ARG & flags)) return 0; if (NetEConst*word_addr = dynamic_cast(word_index)) { @@ -2711,16 +2739,20 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, } if (word_sel == index_component_t::SEL_PART) - return elaborate_expr_net_part_(des, scope, res, found_in, expr_wid); + return elaborate_expr_net_part_(des, scope, res, found_in, + expr_wid); if (word_sel == index_component_t::SEL_IDX_UP) - return elaborate_expr_net_idx_up_(des, scope, res, found_in); + return elaborate_expr_net_idx_up_(des, scope, res, found_in, + need_const); if (word_sel == index_component_t::SEL_IDX_DO) - return elaborate_expr_net_idx_do_(des, scope, res, found_in); + return elaborate_expr_net_idx_do_(des, scope, res, found_in, + need_const); if (word_sel == index_component_t::SEL_BIT) - return elaborate_expr_net_bit_(des, scope, res, found_in); + return elaborate_expr_net_bit_(des, scope, res, found_in, + need_const); ivl_assert(*this, word_sel == index_component_t::SEL_NONE); @@ -2837,9 +2869,10 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, * Part select indexed up, i.e. net[ +: ] */ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, - NetESignal*net, NetScope*) const + NetESignal*net, NetScope*, + bool need_const) const { - NetExpr*base = calculate_up_do_base_(des, scope); + NetExpr*base = calculate_up_do_base_(des, scope, need_const); unsigned long wid = 0; calculate_up_do_width_(des, scope, wid); @@ -2925,9 +2958,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, * Part select indexed down, i.e. net[ -: ] */ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, - NetESignal*net, NetScope*)const + NetESignal*net, NetScope*, + bool need_const) const { - NetExpr*base = calculate_up_do_base_(des, scope); + NetExpr*base = calculate_up_do_base_(des, scope, need_const); unsigned long wid = 0; calculate_up_do_width_(des, scope, wid); @@ -3009,7 +3043,8 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, } NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, - NetESignal*net, NetScope*) const + NetESignal*net, NetScope*, + bool need_const) const { const name_component_t&name_tail = path_.back(); ivl_assert(*this, !name_tail.index.empty()); @@ -3018,7 +3053,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, ivl_assert(*this, index_tail.msb != 0); ivl_assert(*this, index_tail.lsb == 0); - NetExpr*ex = elab_and_eval(des, scope, index_tail.msb, -1); + NetExpr*ex = elab_and_eval(des, scope, index_tail.msb, -1, need_const); // If the bit select is constant, then treat it similar // to the part select, so that I save the effort of @@ -3111,11 +3146,13 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, NetNet*net, NetScope*found_in, unsigned expr_wid, - bool sys_task_arg) const + unsigned flags) const { if (net->array_dimensions() > 0) return elaborate_expr_net_word_(des, scope, net, found_in, - expr_wid, sys_task_arg); + expr_wid, flags); + + bool need_const = NEED_CONST & flags; NetESignal*node = new NetESignal(net); node->set_line(*this); @@ -3143,13 +3180,16 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, expr_wid); if (use_sel == index_component_t::SEL_IDX_UP) - return elaborate_expr_net_idx_up_(des, scope, node, found_in); + return elaborate_expr_net_idx_up_(des, scope, node, found_in, + need_const); if (use_sel == index_component_t::SEL_IDX_DO) - return elaborate_expr_net_idx_do_(des, scope, node, found_in); + return elaborate_expr_net_idx_do_(des, scope, node, found_in, + need_const); if (use_sel == index_component_t::SEL_BIT) - return elaborate_expr_net_bit_(des, scope, node, found_in); + return elaborate_expr_net_bit_(des, scope, node, found_in, + need_const); // It's not anything else, so this must be a simple identifier // expression with no part or bit select. Return the signal @@ -3173,7 +3213,7 @@ unsigned PENumber::test_width(Design*, NetScope*, width_mode_t&mode) } NetEConst* PENumber::elaborate_expr(Design*, NetScope*, - unsigned expr_wid, bool) const + unsigned expr_wid, unsigned) const { assert(value_); verinum val = *value_; @@ -3198,7 +3238,7 @@ unsigned PEString::test_width(Design*, NetScope*, width_mode_t&) } NetEConst* PEString::elaborate_expr(Design*, NetScope*, - unsigned expr_wid, bool) const + unsigned expr_wid, unsigned) const { verinum val(value()); val = pad_to_width(val, expr_wid); @@ -3295,15 +3335,17 @@ bool NetETernary::test_operand_compat(ivl_variable_type_t l, * methods. If any elaboration fails, then give up and return 0. */ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, - unsigned expr_wid, bool) const + unsigned expr_wid, unsigned flags) const { - assert(expr_); - assert(tru_); - assert(fal_); + flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag + + ivl_assert(*this, expr_); + ivl_assert(*this, tru_); + ivl_assert(*this, fal_); // Elaborate and evaluate the condition expression. Note that // it is always self-determined. - NetExpr*con = elab_and_eval(des, scope, expr_, -1); + NetExpr*con = elab_and_eval(des, scope, expr_, -1, NEED_CONST & flags); if (con == 0) return 0; @@ -3326,7 +3368,8 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, "elaborate TRUE clause of ternary." << endl; - return elab_and_eval_alternative_(des, scope, tru_, expr_wid); + return elab_and_eval_alternative_(des, scope, tru_, + expr_wid, flags); } // Condition is constant FALSE, so we only need the @@ -3337,20 +3380,21 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, "elaborate FALSE clause of ternary." << endl; - return elab_and_eval_alternative_(des, scope, fal_, expr_wid); + return elab_and_eval_alternative_(des, scope, fal_, + expr_wid, flags); } // X and Z conditions need to blend both results, so we // can't short-circuit. } - NetExpr*tru = elab_and_eval_alternative_(des, scope, tru_, expr_wid); + NetExpr*tru = elab_and_eval_alternative_(des, scope, tru_, expr_wid, flags); if (tru == 0) { delete con; return 0; } - NetExpr*fal = elab_and_eval_alternative_(des, scope, fal_, expr_wid); + NetExpr*fal = elab_and_eval_alternative_(des, scope, fal_, expr_wid, flags); if (fal == 0) { delete con; delete tru; @@ -3378,7 +3422,8 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, * self-determined. */ NetExpr* PETernary::elab_and_eval_alternative_(Design*des, NetScope*scope, - PExpr*expr, unsigned expr_wid) const + PExpr*expr, unsigned expr_wid, + unsigned flags) const { int context_wid = expr_wid; if (type_is_vectorable(expr->expr_type()) && !type_is_vectorable(expr_type_)) { @@ -3387,7 +3432,7 @@ NetExpr* PETernary::elab_and_eval_alternative_(Design*des, NetScope*scope, } else { expr->cast_signed(signed_flag_); } - NetExpr*tmp = expr->elaborate_expr(des, scope, expr_wid, false); + NetExpr*tmp = expr->elaborate_expr(des, scope, expr_wid, flags); if (tmp == 0) return 0; eval_expr(tmp, context_wid); @@ -3436,8 +3481,10 @@ unsigned PEUnary::test_width(Design*des, NetScope*scope, width_mode_t&mode) NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, - unsigned expr_wid, bool) const + unsigned expr_wid, unsigned flags) const { + flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag + unsigned sub_width = expr_wid; switch (op_) { // Reduction operators and ! always have a self determined width. @@ -3457,7 +3504,7 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, expr_->cast_signed(signed_flag_); break; } - NetExpr*ip = expr_->elaborate_expr(des, scope, sub_width, false); + NetExpr*ip = expr_->elaborate_expr(des, scope, sub_width, flags); if (ip == 0) return 0; ivl_assert(*expr_, expr_type_ != IVL_VT_NO_TYPE); @@ -3604,7 +3651,7 @@ NetExpr* PEUnary::elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const return tmp; } -NetExpr* PEVoid::elaborate_expr(Design*, NetScope*, unsigned, bool) const +NetExpr* PEVoid::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const { return 0; } diff --git a/elab_net.cc b/elab_net.cc index 9ff968c39..2a7d75400 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -222,9 +222,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, case index_component_t::SEL_IDX_DO: case index_component_t::SEL_IDX_UP: { - need_constant_expr = true; - NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1); - need_constant_expr = false; + NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1, true); NetEConst*tmp = dynamic_cast(tmp_ex); if (!tmp) { cerr << get_fileline() << ": error: indexed part select of " @@ -480,9 +478,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, } ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT); - need_constant_expr = true; - NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1); - need_constant_expr = false; + NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1, true); NetEConst*tmp = dynamic_cast(tmp_ex); if (!tmp) { cerr << get_fileline() << ": error: array " << sig->name() diff --git a/elab_scope.cc b/elab_scope.cc index 4bf184661..76f38cacb 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -554,9 +554,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) // The initial value for the genvar does not need (nor can it // use) the genvar itself, so we can evaluate this expression // the same way any other parameter value is evaluated. - need_constant_expr = true; - NetExpr*init_ex = elab_and_eval(des, container, loop_init, -1); - need_constant_expr = false; + NetExpr*init_ex = elab_and_eval(des, container, loop_init, -1, true); NetEConst*init = dynamic_cast (init_ex); if (init == 0) { cerr << get_fileline() << ": error: Cannot evaluate genvar" @@ -620,9 +618,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) cerr << get_fileline() << ": debug: genvar init = " << genvar << endl; container->genvar_tmp = loop_index; container->genvar_tmp_val = genvar; - need_constant_expr = true; - NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1); - need_constant_expr = false; + NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1, true); NetEConst*test = dynamic_cast(test_ex); if (test == 0) { cerr << get_fileline() << ": error: Cannot evaluate genvar" @@ -668,9 +664,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) elaborate_subscope_(des, scope); // Calculate the step for the loop variable. - need_constant_expr = true; - NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1); - need_constant_expr = false; + NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1, true); NetEConst*step = dynamic_cast(step_ex); if (step == 0) { cerr << get_fileline() << ": error: Cannot evaluate genvar" @@ -700,9 +694,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else_flag) { - need_constant_expr = true; - NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1); - need_constant_expr = false; + NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1, true); NetEConst*test = dynamic_cast (test_ex); if (test == 0) { cerr << get_fileline() << ": error: Cannot evaluate genvar" @@ -792,9 +784,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else bool PGenerate::generate_scope_case_(Design*des, NetScope*container) { - need_constant_expr = true; - NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1); - need_constant_expr = false; + NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1, true); NetEConst*case_value_co = dynamic_cast(case_value_ex); if (case_value_co == 0) { cerr << get_fileline() << ": error: Cannot evaluate genvar case" @@ -824,9 +814,9 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container) bool match_flag = false; for (unsigned idx = 0 ; idx < item->item_test.size() && !match_flag ; idx +=1 ) { - need_constant_expr = true; - NetExpr*item_value_ex = elab_and_eval(des, container, item->item_test[idx], -1); - need_constant_expr = false; + NetExpr*item_value_ex = elab_and_eval(des, container, + item->item_test[idx], + -1, true); NetEConst*item_value_co = dynamic_cast(item_value_ex); if (item_value_co == 0) { cerr << get_fileline() << ": error: Cannot evaluate " @@ -1196,10 +1186,8 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const */ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const { - need_constant_expr = true; - NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1) : 0; - NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1) : 0; - need_constant_expr = false; + NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1, true) : 0; + NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1, true) : 0; NetEConst*msb = dynamic_cast (mse); NetEConst*lsb = dynamic_cast (lse); diff --git a/elab_sig.cc b/elab_sig.cc index 35312e442..edbdc2eae 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -35,14 +35,6 @@ # include "util.h" # include "ivl_assert.h" -/* - * Set the following to true when you need to process an expression - * that is being done in a constant context. This allows the - * elaboration to explicitly say we do not currently support constant - * user functions when the function is not found. - */ -bool need_constant_expr = false; - static bool get_const_argument(NetExpr*exp, verinum&res) { switch (exp->expr_type()) { @@ -472,14 +464,14 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const if (return_type_.range) { ivl_assert(*this, return_type_.range->size() == 2); - need_constant_expr = true; NetExpr*me = elab_and_eval(des, scope, - return_type_.range->at(0), -1); + return_type_.range->at(0), -1, + true); assert(me); NetExpr*le = elab_and_eval(des, scope, - return_type_.range->at(1), -1); + return_type_.range->at(1), -1, + true); assert(le); - need_constant_expr = false; long mnum = 0, lnum = 0; if ( ! get_const_argument(me, mnum) ) { @@ -545,14 +537,14 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const ivl_assert(*this, return_type_.range != 0); long use_wid; { - need_constant_expr = true; NetExpr*me = elab_and_eval(des, scope, - (*return_type_.range)[0], -1); + (*return_type_.range)[0], -1, + true); assert(me); NetExpr*le = elab_and_eval(des, scope, - (*return_type_.range)[1], -1); + (*return_type_.range)[1], -1, + true); assert(le); - need_constant_expr = false; long mnum = 0, lnum = 0; if ( ! get_const_argument(me, mnum) ) { @@ -848,10 +840,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const bool bad_lsb = false, bad_msb = false; /* If they exist get the port definition MSB and LSB */ if (port_set_ && port_msb_ != 0) { - /* We do not currently support constant user function. */ - need_constant_expr = true; - NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1); - need_constant_expr = false; + NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1, true); if (! eval_as_long(pmsb, texpr)) { cerr << port_msb_->get_fileline() << ": error: " @@ -865,10 +854,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const delete texpr; - /* We do not currently support constant user function. */ - need_constant_expr = true; - texpr = elab_and_eval(des, scope, port_lsb_, -1); - need_constant_expr = false; + texpr = elab_and_eval(des, scope, port_lsb_, -1, true); if (! eval_as_long(plsb, texpr)) { cerr << port_lsb_->get_fileline() << ": error: " @@ -892,10 +878,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const /* If they exist get the net/etc. definition MSB and LSB */ if (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) { - /* We do not currently support constant user function. */ - need_constant_expr = true; - NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1); - need_constant_expr = false; + NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1, true); if (! eval_as_long(nmsb, texpr)) { cerr << net_msb_->get_fileline() << ": error: " @@ -909,10 +892,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const delete texpr; - /* We do not currently support constant user function. */ - need_constant_expr = true; - texpr = elab_and_eval(des, scope, net_lsb_, -1); - need_constant_expr = false; + texpr = elab_and_eval(des, scope, net_lsb_, -1, true); if (! eval_as_long(nlsb, texpr)) { cerr << net_lsb_->get_fileline() << ": error: " @@ -1003,10 +983,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (lidx_ || ridx_) { assert(lidx_ && ridx_); - need_constant_expr = true; - NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1); - NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1); - need_constant_expr = false; + NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1, true); + NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1, true); if ((lexp == 0) || (rexp == 0)) { cerr << get_fileline() << ": internal error: There is " diff --git a/elaborate.cc b/elaborate.cc index a1e0e5a49..a37dd0f1c 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -227,10 +227,8 @@ unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope, gates, then I am expected to make more than one gate. Figure out how many are desired. */ if (msb_) { - need_constant_expr = true; - NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1); - NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1); - need_constant_expr = false; + NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1, true); + NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1, true); NetEConst*msb_con = dynamic_cast(msb_exp); NetEConst*lsb_con = dynamic_cast(lsb_exp); @@ -2057,9 +2055,8 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, { ivl_assert(*this, rval_); - need_constant_expr = is_constant_; - NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, lv_width, rval()); - need_constant_expr = false; + NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, lv_width, rval(), + is_constant_); if (!is_constant_ || !rv) return rv; @@ -3376,7 +3373,8 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope, PExpr::width_mode_t mode; pe->test_width(des, scope, mode); - NetExpr*expr = pe->elaborate_expr(des, scope, pe->expr_width(), false); + NetExpr*expr = pe->elaborate_expr(des, scope, pe->expr_width(), + PExpr::NO_FLAGS); if (expr == 0) { cerr << get_fileline() << ": error: Unable to elaborate" " wait condition expression." << endl; @@ -4204,9 +4202,8 @@ bool Module::elaborate(Design*des, NetScope*scope) const for (specparam_it_t cur = specparams.begin() ; cur != specparams.end() ; ++ cur ) { - need_constant_expr = true; - NetExpr*val = elab_and_eval(des, scope, (*cur).second, -1); - need_constant_expr = false; + NetExpr*val = elab_and_eval(des, scope, (*cur).second, -1, + true); NetScope::spec_val_t value; if (NetECReal*val_cr = dynamic_cast (val)) { diff --git a/eval_tree.cc b/eval_tree.cc index 5fc9831c2..2d6f2e607 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1946,12 +1946,5 @@ NetExpr* NetESFunc::eval_tree() NetExpr* NetEUFunc::eval_tree() { - if (need_constant_expr) { - cerr << get_fileline() << ": sorry: constant user " - "functions are not currently supported: " - << func_->basename() << "()." << endl; - - } - return 0; } diff --git a/net_design.cc b/net_design.cc index 31296aa63..59c7ebf55 100644 --- a/net_design.cc +++ b/net_design.cc @@ -332,7 +332,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) /* Evaluate the msb expression, if it is present. */ PExpr*msb_expr = (*cur).second.msb_expr; if (msb_expr) { - (*cur).second.msb = elab_and_eval(des, this, msb_expr, -1); + (*cur).second.msb = elab_and_eval(des, this, msb_expr, -1, true); if (! eval_as_long(msb, (*cur).second.msb)) { cerr << (*cur).second.val->get_fileline() << ": error: Unable to evaluate msb expression " @@ -348,7 +348,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) /* Evaluate the lsb expression, if it is present. */ PExpr*lsb_expr = (*cur).second.lsb_expr; if (lsb_expr) { - (*cur).second.lsb = elab_and_eval(des, this, lsb_expr, -1); + (*cur).second.lsb = elab_and_eval(des, this, lsb_expr, -1, true); if (! eval_as_long(lsb, (*cur).second.lsb)) { cerr << (*cur).second.val->get_fileline() << ": error: Unable to evaluate lsb expression " @@ -369,7 +369,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) if (range_flag) lv_width = (msb >= lsb) ? 1 + msb - lsb : 1 + lsb - msb; - NetExpr*expr = elab_and_eval(des, val_scope, val_expr, lv_width); + NetExpr*expr = elab_and_eval(des, val_scope, val_expr, lv_width, true); if (! expr) return; @@ -488,7 +488,7 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur) PExpr*val_expr = (*cur).second.val_expr; NetScope*val_scope = (*cur).second.val_scope; - NetExpr*expr = elab_and_eval(des, val_scope, val_expr, -1); + NetExpr*expr = elab_and_eval(des, val_scope, val_expr, -1, true); if (! expr) return; @@ -631,14 +631,6 @@ void NetScope::evaluate_parameter_(Design*des, param_ref_t cur) cur->second.val_expr = 0; } -/* - * Set the following to true when evaluating the parameter expressions. - * This causes PEIdent::elaborate_expr() to report an error if an - * identifier in an expression is anything other than a non-hierarchical - * parameter name. - */ -bool is_param_expr = false; - void NetScope::evaluate_parameters(Design*des) { for (map::const_iterator cur = children_.begin() @@ -649,13 +641,11 @@ void NetScope::evaluate_parameters(Design*des) cerr << ":0" << ": debug: " << "Evaluate parameters in " << scope_path(this) << endl; - is_param_expr = true; for (param_ref_t cur = parameters.begin() ; cur != parameters.end() ; ++ cur) { evaluate_parameter_(des, cur); } - is_param_expr = false; } void Design::residual_defparams() diff --git a/netmisc.cc b/netmisc.cc index 42657c7bc..6bb216e85 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -470,7 +470,8 @@ static const char*width_mode_name(PExpr::width_mode_t mode) } } -NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, int context_width) +NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, + int context_width, bool need_const) { PExpr::width_mode_t mode = PExpr::SIZED; if ((context_width == -2) && !gn_strict_expr_width_flag) @@ -510,7 +511,11 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, int context_width) } } - NetExpr*tmp = pe->elaborate_expr(des, scope, expr_width, false); + unsigned flags = PExpr::NO_FLAGS; + if (need_const) + flags |= PExpr::NEED_CONST; + + NetExpr*tmp = pe->elaborate_expr(des, scope, expr_width, flags); if (tmp == 0) return 0; eval_expr(tmp, context_width); @@ -524,7 +529,7 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, int context_width) } NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name, - unsigned arg_idx, PExpr*pe) + unsigned arg_idx, PExpr*pe, bool need_const) { PExpr::width_mode_t mode = PExpr::SIZED; pe->test_width(des, scope, mode); @@ -539,7 +544,11 @@ NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name, << ", mode=" << width_mode_name(mode) << endl; } - NetExpr*tmp = pe->elaborate_expr(des, scope, pe->expr_width(), true); + unsigned flags = PExpr::SYS_TASK_ARG; + if (need_const) + flags |= PExpr::NEED_CONST; + + NetExpr*tmp = pe->elaborate_expr(des, scope, pe->expr_width(), flags); if (tmp == 0) return 0; eval_expr(tmp, -1); diff --git a/netmisc.h b/netmisc.h index f056c933f..20d72461f 100644 --- a/netmisc.h +++ b/netmisc.h @@ -134,17 +134,6 @@ extern NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid); */ extern unsigned count_lval_width(const class NetAssign_*first); -/* - * This is temporarily used to indicate that a user function elaboration - * fail is likely the result of missing constant user function support. - */ -extern bool need_constant_expr; - -/* - * This is used to indicate that we are evaluating a parameter expression. - */ -extern bool is_param_expr; - /* * This function elaborates an expression, and tries to evaluate it * right away. If the expression can be evaluated, this returns a @@ -160,14 +149,16 @@ extern bool is_param_expr; class PExpr; extern NetExpr* elab_and_eval(Design*des, NetScope*scope, - PExpr*pe, int context_width); + PExpr*pe, int context_width, + bool need_const =false); /* * This function is a variant of elab_and_eval that elaborates and * evaluates the arguments of a system task. */ -extern NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name, - unsigned arg_idx, PExpr*pe); +extern NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, + perm_string name, unsigned arg_idx, + PExpr*pe, bool need_const =false); /* * This function elaborates an expression as if it is for the r-value * of an assignment, The lv_type and lv_width are the type and width @@ -176,7 +167,8 @@ extern NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name, */ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_variable_type_t lv_type, - unsigned lv_width, PExpr*expr); + unsigned lv_width, PExpr*expr, + bool need_const =false); /* * This procedure evaluates an expression and if the evaluation is