Rework of constant expression error reporting.

This patch changes the method used to signal that a constant expression
is being elaborated from flags stored in global variables to flags
passed down the call chain. It also generates more informative error
messages when variable references are found in a constant expression.
This commit is contained in:
Martin Whitaker 2011-03-27 11:08:33 +01:00 committed by Stephen Williams
parent 240880d81b
commit 93067149f1
10 changed files with 252 additions and 249 deletions

63
PExpr.h
View File

@ -45,6 +45,11 @@ class PExpr : public LineInfo {
public: public:
enum width_mode_t { SIZED, EXPAND, LOSSLESS, UNSIZED }; 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(); PExpr();
virtual ~PExpr(); virtual ~PExpr();
@ -122,7 +127,7 @@ class PExpr : public LineInfo {
// be incomplete. // be incomplete.
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
// This method elaborates the expression as gates, but // This method elaborates the expression as gates, but
// restricted for use as l-values of continuous assignments. // 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 NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
virtual NetAssign_* elaborate_lval(Design*des, virtual NetAssign_* elaborate_lval(Design*des,
NetScope*scope, NetScope*scope,
bool is_force) const; bool is_force) const;
@ -261,7 +266,7 @@ class PEFNumber : public PExpr {
width_mode_t&mode); width_mode_t&mode);
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
@ -301,7 +306,7 @@ class PEIdent : public PExpr {
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
// Elaborate the PEIdent as a port to a module. This method // Elaborate the PEIdent as a port to a module. This method
// only applies to Ident expressions. // only applies to Ident expressions.
@ -330,7 +335,7 @@ class PEIdent : public PExpr {
// invalid bits (xz) in either expression, then the defined // invalid bits (xz) in either expression, then the defined
// flag is set to *false*. // flag is set to *false*.
bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb, bool&defined) const; 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*, bool calculate_param_range_(Design*, NetScope*,
const NetExpr*msb_ex, long&msb, const NetExpr*msb_ex, long&msb,
const NetExpr*lsb_ex, long&lsb, const NetExpr*lsb_ex, long&lsb,
@ -352,7 +357,8 @@ class PEIdent : public PExpr {
NetScope*found, NetScope*found,
const NetExpr*par_msb, const NetExpr*par_msb,
const NetExpr*par_lsb, const NetExpr*par_lsb,
unsigned expr_wid) const; unsigned expr_wid,
unsigned flags) const;
NetExpr*elaborate_expr_param_part_(Design*des, NetExpr*elaborate_expr_param_part_(Design*des,
NetScope*scope, NetScope*scope,
const NetExpr*par, const NetExpr*par,
@ -365,25 +371,27 @@ class PEIdent : public PExpr {
const NetExpr*par, const NetExpr*par,
NetScope*found, NetScope*found,
const NetExpr*par_msb, 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, NetExpr*elaborate_expr_param_idx_do_(Design*des,
NetScope*scope, NetScope*scope,
const NetExpr*par, const NetExpr*par,
NetScope*found, NetScope*found,
const NetExpr*par_msb, const NetExpr*par_msb,
const NetExpr*par_lsb) const; const NetExpr*par_lsb,
bool need_const) const;
NetExpr*elaborate_expr_net(Design*des, NetExpr*elaborate_expr_net(Design*des,
NetScope*scope, NetScope*scope,
NetNet*net, NetNet*net,
NetScope*found, NetScope*found,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
NetExpr*elaborate_expr_net_word_(Design*des, NetExpr*elaborate_expr_net_word_(Design*des,
NetScope*scope, NetScope*scope,
NetNet*net, NetNet*net,
NetScope*found, NetScope*found,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
NetExpr*elaborate_expr_net_part_(Design*des, NetExpr*elaborate_expr_net_part_(Design*des,
NetScope*scope, NetScope*scope,
NetESignal*net, NetESignal*net,
@ -392,15 +400,18 @@ class PEIdent : public PExpr {
NetExpr*elaborate_expr_net_idx_up_(Design*des, NetExpr*elaborate_expr_net_idx_up_(Design*des,
NetScope*scope, NetScope*scope,
NetESignal*net, NetESignal*net,
NetScope*found) const; NetScope*found,
bool need_const) const;
NetExpr*elaborate_expr_net_idx_do_(Design*des, NetExpr*elaborate_expr_net_idx_do_(Design*des,
NetScope*scope, NetScope*scope,
NetESignal*net, NetESignal*net,
NetScope*found) const; NetScope*found,
bool need_const) const;
NetExpr*elaborate_expr_net_bit_(Design*des, NetExpr*elaborate_expr_net_bit_(Design*des,
NetScope*scope, NetScope*scope,
NetESignal*net, NetESignal*net,
NetScope*found) const; NetScope*found,
bool need_const) const;
private: private:
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope, NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
@ -423,7 +434,7 @@ class PENumber : public PExpr {
width_mode_t&mode); width_mode_t&mode);
virtual NetEConst*elaborate_expr(Design*des, NetScope*, virtual NetEConst*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid, bool) const; unsigned expr_wid, unsigned) const;
virtual NetAssign_* elaborate_lval(Design*des, virtual NetAssign_* elaborate_lval(Design*des,
NetScope*scope, NetScope*scope,
bool is_force) const; bool is_force) const;
@ -456,7 +467,7 @@ class PEString : public PExpr {
width_mode_t&mode); width_mode_t&mode);
virtual NetEConst*elaborate_expr(Design*des, NetScope*, virtual NetEConst*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid, bool) const; unsigned expr_wid, unsigned) const;
verinum* eval_const(Design*, NetScope*) const; verinum* eval_const(Design*, NetScope*) const;
private: private:
@ -480,7 +491,7 @@ class PEUnary : public PExpr {
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
virtual verinum* eval_const(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const;
private: private:
@ -508,7 +519,7 @@ class PEBinary : public PExpr {
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
virtual verinum* eval_const(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const;
protected: protected:
@ -546,7 +557,7 @@ class PEBComp : public PEBinary {
width_mode_t&mode); width_mode_t&mode);
NetExpr* elaborate_expr(Design*des, NetScope*scope, NetExpr* elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid, bool sys_task_arg) const; unsigned expr_wid, unsigned flags) const;
private: private:
unsigned l_width_; unsigned l_width_;
@ -566,7 +577,7 @@ class PEBLogic : public PEBinary {
width_mode_t&mode); width_mode_t&mode);
NetExpr* elaborate_expr(Design*des, NetScope*scope, 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, virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
}; };
class PEBPower : public PEBLeftWidth { class PEBPower : public PEBLeftWidth {
@ -633,12 +644,13 @@ class PETernary : public PExpr {
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
virtual verinum* eval_const(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const;
private: private:
NetExpr* elab_and_eval_alternative_(Design*des, NetScope*scope, NetExpr* elab_and_eval_alternative_(Design*des, NetScope*scope,
PExpr*expr, unsigned expr_wid) const; PExpr*expr, unsigned expr_wid,
unsigned flags) const;
private: private:
PExpr*expr_; PExpr*expr_;
@ -672,7 +684,7 @@ class PECallFunction : public PExpr {
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
width_mode_t&mode); width_mode_t&mode);
@ -686,7 +698,8 @@ class PECallFunction : public PExpr {
NetExpr* cast_to_width_(NetExpr*expr, unsigned wid) const; NetExpr* cast_to_width_(NetExpr*expr, unsigned wid) const;
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, 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, NetExpr* elaborate_access_func_(Design*des, NetScope*scope, ivl_nature_t,
unsigned expr_wid) const; unsigned expr_wid) const;
unsigned test_width_sfunc_(Design*des, NetScope*scope, unsigned test_width_sfunc_(Design*des, NetScope*scope,
@ -705,7 +718,7 @@ class PEVoid : public PExpr {
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const; unsigned flags) const;
}; };
#endif #endif

View File

@ -82,7 +82,7 @@ static NetBranch* find_existing_implicit_branch(NetNet*sig, NetNet*gnd)
NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
ivl_variable_type_t lv_type, unsigned lv_width, ivl_variable_type_t lv_type, unsigned lv_width,
PExpr*expr) PExpr*expr, bool need_const)
{ {
int context_wid = -1; int context_wid = -1;
switch (lv_type) { switch (lv_type) {
@ -99,7 +99,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
break; 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; 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" cerr << get_fileline() << ": internal error: I do not know how to"
<< " elaborate this expression. " << endl; << " elaborate this expression. " << endl;
@ -224,8 +224,10 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
* types. * types.
*/ */
NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope, 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, left_);
ivl_assert(*this, right_); ivl_assert(*this, right_);
@ -249,8 +251,8 @@ NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope,
left_->cast_signed(signed_flag_); left_->cast_signed(signed_flag_);
} }
NetExpr*lp = left_->elaborate_expr(des, scope, l_width, false); NetExpr*lp = left_->elaborate_expr(des, scope, l_width, flags);
NetExpr*rp = right_->elaborate_expr(des, scope, r_width, false); NetExpr*rp = right_->elaborate_expr(des, scope, r_width, flags);
if ((lp == 0) || (rp == 0)) { if ((lp == 0) || (rp == 0)) {
delete lp; delete lp;
delete rp; 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, 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, left_);
ivl_assert(*this, right_); 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()) if (type_is_vectorable(right_->expr_type()) && !right_->has_sign())
left_->cast_signed(false); left_->cast_signed(false);
NetExpr*lp = left_->elaborate_expr(des, scope, l_width_, false); NetExpr*lp = left_->elaborate_expr(des, scope, l_width_, flags);
NetExpr*rp = right_->elaborate_expr(des, scope, r_width_, false); NetExpr*rp = right_->elaborate_expr(des, scope, r_width_, flags);
if ((lp == 0) || (rp == 0)) { if ((lp == 0) || (rp == 0)) {
delete lp; delete lp;
delete rp; delete rp;
@ -569,13 +573,14 @@ unsigned PEBLogic::test_width(Design*, NetScope*, width_mode_t&)
} }
NetExpr*PEBLogic::elaborate_expr(Design*des, NetScope*scope, 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, left_);
ivl_assert(*this, right_); ivl_assert(*this, right_);
NetExpr*lp = elab_and_eval(des, scope, left_, -1); bool need_const = NEED_CONST & flags;
NetExpr*rp = elab_and_eval(des, scope, right_, -1); 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)) { if ((lp == 0) || (rp == 0)) {
delete lp; delete lp;
delete rp; 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 // If the right operand is constant, we can use the
// actual value. // 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) { if (rp) {
eval_expr(rp, r_width); eval_expr(rp, r_width);
} else { } 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, 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_); ivl_assert(*this, left_);
// The left operand is always context determined, so propagate // 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(); unsigned r_width = right_->expr_width();
NetExpr*lp = left_->elaborate_expr(des, scope, expr_wid, false); NetExpr*lp = left_->elaborate_expr(des, scope, expr_wid, flags);
NetExpr*rp = right_->elaborate_expr(des, scope, r_width, false); NetExpr*rp = right_->elaborate_expr(des, scope, r_width, flags);
if (lp == 0 || rp == 0) { if (lp == 0 || rp == 0) {
delete lp; delete lp;
delete rp; delete rp;
@ -1074,7 +1081,8 @@ NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const
* known function names. * known function names.
*/ */
NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, 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_); perm_string name = peek_tail_name(path_);
@ -1090,7 +1098,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
} }
PExpr*expr = parms_[0]; 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); 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 as much as possible, and use the reduced
expression if one is created. */ expression if one is created. */
bool need_const = NEED_CONST & flags;
unsigned missing_parms = 0; unsigned missing_parms = 0;
for (unsigned idx = 0 ; idx < nparms ; idx += 1) { for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
PExpr*expr = parms_[idx]; PExpr*expr = parms_[idx];
if (expr) { 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); fun->parm(idx, tmp);
} else { } else {
@ -1250,10 +1261,12 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
} }
NetExpr* PECallFunction::elaborate_expr(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] == '$') 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_); NetFuncDef*def = des->find_function(scope, path_);
if (def == 0) { if (def == 0) {
@ -1268,7 +1281,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
// We do not currently support constant user function and // We do not currently support constant user function and
// this is where things fail because of that, though we // this is where things fail because of that, though we
// don't know for sure so we need to display both messages. // 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 " cerr << get_fileline() << ": sorry: constant user "
"functions are not currently supported: " "functions are not currently supported: "
<< path_ << "()." << endl << " or" << endl; << 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 of the function being called. The scope of the called
function is elaborated when the definition is elaborated. */ function is elaborated when the definition is elaborated. */
bool need_const = NEED_CONST & flags;
unsigned missing_parms = 0; unsigned missing_parms = 0;
for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) { for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) {
PExpr*tmp = parms_[idx]; PExpr*tmp = parms_[idx];
@ -1304,7 +1319,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
parms[idx] = elaborate_rval_expr(des, scope, parms[idx] = elaborate_rval_expr(des, scope,
def->port(idx)->data_type(), def->port(idx)->data_type(),
(unsigned)def->port(idx)->vector_width(), (unsigned)def->port(idx)->vector_width(),
tmp); tmp, need_const);
if (NetEEvent*evt = dynamic_cast<NetEEvent*> (parms[idx])) { if (NetEEvent*evt = dynamic_cast<NetEEvent*> (parms[idx])) {
cerr << evt->get_fileline() << ": error: An event '" cerr << evt->get_fileline() << ": error: An event '"
<< evt->event()->name() << "' can not be a user " << 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 /* If there is a repeat expression, then evaluate the constant
value and set the repeat count. */ value and set the repeat count. */
if (repeat_ && (scope != tested_scope_)) { if (repeat_ && (scope != tested_scope_)) {
need_constant_expr = true; NetExpr*tmp = elab_and_eval(des, scope, repeat_, -1, true);
NetExpr*tmp = elab_and_eval(des, scope, repeat_, -1);
need_constant_expr = false;
if (tmp == 0) return 0; if (tmp == 0) return 0;
if (tmp->expr_type() == IVL_VT_REAL) { 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; static int concat_depth = 0;
NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, 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; concat_depth += 1;
if (debug_elaborate) { if (debug_elaborate) {
@ -1459,7 +1474,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
assert(parms_[idx]); assert(parms_[idx]);
unsigned wid = parms_[idx]->expr_width(); 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; if (ex == 0) continue;
ex->set_line(*parms_[idx]); ex->set_line(*parms_[idx]);
@ -1542,7 +1557,7 @@ unsigned PEFNumber::test_width(Design*, NetScope*, width_mode_t&)
return expr_width_; 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_); NetECReal*tmp = new NetECReal(*value_);
tmp->set_line(*this); tmp->set_line(*this);
@ -1569,9 +1584,7 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope,
two bit select expressions, and both must be two bit select expressions, and both must be
constant. Evaluate them and pass the results back to constant. Evaluate them and pass the results back to
the caller. */ the caller. */
need_constant_expr = true; NetExpr*lsb_ex = elab_and_eval(des, scope, index_tail.lsb, -1, true);
NetExpr*lsb_ex = elab_and_eval(des, scope, index_tail.lsb, -1);
need_constant_expr = false;
NetEConst*lsb_c = dynamic_cast<NetEConst*>(lsb_ex); NetEConst*lsb_c = dynamic_cast<NetEConst*>(lsb_ex);
if (lsb_c == 0) { if (lsb_c == 0) {
cerr << index_tail.lsb->get_fileline() << ": error: " 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(); lsb = lsb_c->value().as_long();
} }
need_constant_expr = true; NetExpr*msb_ex = elab_and_eval(des, scope, index_tail.msb, -1, true);
NetExpr*msb_ex = elab_and_eval(des, scope, index_tail.msb, -1);
need_constant_expr = false;
NetEConst*msb_c = dynamic_cast<NetEConst*>(msb_ex); NetEConst*msb_c = dynamic_cast<NetEConst*>(msb_ex);
if (msb_c == 0) { if (msb_c == 0) {
cerr << index_tail.msb->get_fileline() << ": error: " 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) /* Calculate the width expression (in the lsb_ position)
first. If the expression is not constant, error but guess 1 first. If the expression is not constant, error but guess 1
so we can keep going and find more errors. */ 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, true);
NetExpr*wid_ex = elab_and_eval(des, scope, index_tail.lsb, -1);
need_constant_expr = false;
NetEConst*wid_c = dynamic_cast<NetEConst*>(wid_ex); NetEConst*wid_c = dynamic_cast<NetEConst*>(wid_ex);
if (wid_c == 0) { 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 * 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. * 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(); const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty()); 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.lsb != 0);
ivl_assert(*this, index_tail.msb != 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; 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. * The signal name may be escaped, but that affects nothing here.
*/ */
NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid, bool sys_task_arg) const unsigned expr_wid, unsigned flags) const
{ {
assert(scope); assert(scope);
@ -1841,10 +1851,10 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
const NetExpr*ex1, *ex2; const NetExpr*ex1, *ex2;
if (is_param_expr && path_.size() > 1) { if ((NEED_CONST & flags) && (path_.size() > 1)) {
cerr << get_fileline() << ": error: parameter r-value expression " cerr << get_fileline() << ": error: A hierarchical reference ('"
"does not support hierarchical references `" << path_ << path_ << "') is not allowed in a constant expression."
<< "`." << endl; << endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
} }
@ -1857,7 +1867,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
// the parameter value. // the parameter value.
if (par != 0) { if (par != 0) {
NetExpr*tmp = elaborate_expr_param_(des, scope, par, found_in, NetExpr*tmp = elaborate_expr_param_(des, scope, par, found_in,
ex1, ex2, expr_wid); ex1, ex2, expr_wid, flags);
if (!tmp) return 0; if (!tmp) return 0;
@ -1867,20 +1877,19 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
return tmp; 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) // If the identifier names a signal (a register or wire)
// then create a NetESignal node to handle it. // then create a NetESignal node to handle it.
if (net != 0) { 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, NetExpr*tmp = elaborate_expr_net(des, scope, net, found_in,
expr_wid, sys_task_arg); expr_wid, flags);
if (!tmp) return 0; if (!tmp) return 0;
@ -1890,9 +1899,17 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
return tmp; return tmp;
} }
// If the identifier is a named event. // If the identifier is a named event
// is a variable reference. // then create a NetEEvent node to handle it.
if (eve != 0) { 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); NetEEvent*tmp = new NetEEvent(eve);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
@ -1987,7 +2004,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
} }
NetExpr*expr = elaborate_expr_net(des, scope, net, found_in, NetExpr*expr = elaborate_expr_net(des, scope, net, found_in,
expr_wid, false); expr_wid, NO_FLAGS);
NetESFunc*sys_expr = 0; NetESFunc*sys_expr = 0;
if (method_name == "name") { if (method_name == "name") {
@ -2007,7 +2024,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
<< " attached to " << use_path << "." << endl; << " attached to " << use_path << "." << endl;
des->errors += 1; des->errors += 1;
return elaborate_expr_net(des, scope, net, found_in, return elaborate_expr_net(des, scope, net, found_in,
expr_wid, false); expr_wid, NO_FLAGS);
} }
sys_expr->set_line(*this); 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 // are not scopes. If this is not a system task argument, then
// it cannot be a scope name, so give up. // 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. // I cannot interpret this identifier. Error message.
cerr << get_fileline() << ": error: Unable to bind wire/reg/memory " cerr << get_fileline() << ": error: Unable to bind "
"`" << path_ << "' in `" << scope_path(scope) << "'"<< endl; << (NEED_CONST & flags ? "parameter" : "wire/reg/memory")
<< " `" << path_ << "' in `" << scope_path(scope) << "'"
<< endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
} }
@ -2063,7 +2082,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
<< nsc->basename() << nsc->basename()
<< " path=" << path_ << endl; << " path=" << path_ << endl;
if (! sys_task_arg) { if ( !(SYS_TASK_ARG & flags) ) {
cerr << get_fileline() << ": error: Scope name " cerr << get_fileline() << ": error: Scope name "
<< nsc->basename() << " not allowed here." << endl; << nsc->basename() << " not allowed here." << endl;
des->errors += 1; des->errors += 1;
@ -2248,7 +2267,8 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
const NetExpr*par, const NetExpr*par,
NetScope*, NetScope*,
const NetExpr*par_msb, const NetExpr*par_msb,
const NetExpr*par_lsb) const const NetExpr*par_lsb,
bool need_const) const
{ {
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par); const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
ivl_assert(*this, par_ex); 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_lsb, par_lsv,
par_ex->value().len())) return 0; 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; if (base == 0) return 0;
unsigned long wid = 0; unsigned long wid = 0;
@ -2327,7 +2347,8 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
const NetExpr*par, const NetExpr*par,
NetScope*, NetScope*,
const NetExpr*par_msb, const NetExpr*par_msb,
const NetExpr*par_lsb) const const NetExpr*par_lsb,
bool need_const) const
{ {
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par); const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
ivl_assert(*this, par_ex); 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_lsb, par_lsv,
par_ex->value().len())) return 0; 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; if (base == 0) return 0;
unsigned long wid = 0; unsigned long wid = 0;
@ -2414,8 +2435,10 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
NetScope*found_in, NetScope*found_in,
const NetExpr*par_msb, const NetExpr*par_msb,
const NetExpr*par_lsb, 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(); const name_component_t&name_tail = path_.back();
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty()) 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) if (use_sel == index_component_t::SEL_IDX_UP)
return elaborate_expr_param_idx_up_(des, scope, par, found_in, 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) if (use_sel == index_component_t::SEL_IDX_DO)
return elaborate_expr_param_idx_do_(des, scope, par, found_in, 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 // NOTE TO SELF (continued): The code below should be
// rewritten in the above format, as I get to it. // 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 /* Handle the case where a parameter has a bit
select attached to it. Generate a NetESelect select attached to it. Generate a NetESelect
object to select the bit as desired. */ 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 /* Let's first try to get constant values for both
the parameter and the bit select. If they are 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, NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in, NetNet*net, NetScope*found_in,
unsigned expr_wid, 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(); 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() cerr << get_fileline() << ": error: Array " << path()
<< " Needs an array index here." << endl; << " Needs an array index here." << endl;
des->errors += 1; des->errors += 1;
@ -2647,10 +2673,12 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
ivl_assert(*this, !index_front.lsb); ivl_assert(*this, !index_front.lsb);
} }
NetExpr*word_index = index_front.sel == index_component_t::SEL_NONE NetExpr*word_index = 0;
? 0 if (index_front.sel != index_component_t::SEL_NONE)
: elab_and_eval(des, scope, index_front.msb, -1); word_index = elab_and_eval(des, scope, index_front.msb, -1,
if (word_index == 0 && !sys_task_arg) need_const);
if (word_index == 0 && !(SYS_TASK_ARG & flags))
return 0; return 0;
if (NetEConst*word_addr = dynamic_cast<NetEConst*>(word_index)) { if (NetEConst*word_addr = dynamic_cast<NetEConst*>(word_index)) {
@ -2711,16 +2739,20 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
} }
if (word_sel == index_component_t::SEL_PART) 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) 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) 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) 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); 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[<m> +: <l>] * Part select indexed up, i.e. net[<m> +: <l>]
*/ */
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, 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; unsigned long wid = 0;
calculate_up_do_width_(des, scope, wid); 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[<m> -: <l>] * Part select indexed down, i.e. net[<m> -: <l>]
*/ */
NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, 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; unsigned long wid = 0;
calculate_up_do_width_(des, scope, wid); 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, 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(); const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty()); 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.msb != 0);
ivl_assert(*this, index_tail.lsb == 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 // If the bit select is constant, then treat it similar
// to the part select, so that I save the effort of // 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, NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in, NetNet*net, NetScope*found_in,
unsigned expr_wid, unsigned expr_wid,
bool sys_task_arg) const unsigned flags) const
{ {
if (net->array_dimensions() > 0) if (net->array_dimensions() > 0)
return elaborate_expr_net_word_(des, scope, net, found_in, 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); NetESignal*node = new NetESignal(net);
node->set_line(*this); node->set_line(*this);
@ -3143,13 +3180,16 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
expr_wid); expr_wid);
if (use_sel == index_component_t::SEL_IDX_UP) 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) 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) 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 // It's not anything else, so this must be a simple identifier
// expression with no part or bit select. Return the signal // 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*, NetEConst* PENumber::elaborate_expr(Design*, NetScope*,
unsigned expr_wid, bool) const unsigned expr_wid, unsigned) const
{ {
assert(value_); assert(value_);
verinum val = *value_; verinum val = *value_;
@ -3198,7 +3238,7 @@ unsigned PEString::test_width(Design*, NetScope*, width_mode_t&)
} }
NetEConst* PEString::elaborate_expr(Design*, NetScope*, NetEConst* PEString::elaborate_expr(Design*, NetScope*,
unsigned expr_wid, bool) const unsigned expr_wid, unsigned) const
{ {
verinum val(value()); verinum val(value());
val = pad_to_width(val, expr_wid); 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. * methods. If any elaboration fails, then give up and return 0.
*/ */
NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid, bool) const unsigned expr_wid, unsigned flags) const
{ {
assert(expr_); flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
assert(tru_);
assert(fal_); ivl_assert(*this, expr_);
ivl_assert(*this, tru_);
ivl_assert(*this, fal_);
// Elaborate and evaluate the condition expression. Note that // Elaborate and evaluate the condition expression. Note that
// it is always self-determined. // 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) if (con == 0)
return 0; return 0;
@ -3326,7 +3368,8 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope,
"elaborate TRUE clause of ternary." "elaborate TRUE clause of ternary."
<< endl; << 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 // 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." "elaborate FALSE clause of ternary."
<< endl; << 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 // X and Z conditions need to blend both results, so we
// can't short-circuit. // 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) { if (tru == 0) {
delete con; delete con;
return 0; 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) { if (fal == 0) {
delete con; delete con;
delete tru; delete tru;
@ -3378,7 +3422,8 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope,
* self-determined. * self-determined.
*/ */
NetExpr* PETernary::elab_and_eval_alternative_(Design*des, NetScope*scope, 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; int context_wid = expr_wid;
if (type_is_vectorable(expr->expr_type()) && !type_is_vectorable(expr_type_)) { 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 { } else {
expr->cast_signed(signed_flag_); 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; if (tmp == 0) return 0;
eval_expr(tmp, context_wid); 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, 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; unsigned sub_width = expr_wid;
switch (op_) { switch (op_) {
// Reduction operators and ! always have a self determined width. // 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_); expr_->cast_signed(signed_flag_);
break; 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; if (ip == 0) return 0;
ivl_assert(*expr_, expr_type_ != IVL_VT_NO_TYPE); 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; return tmp;
} }
NetExpr* PEVoid::elaborate_expr(Design*, NetScope*, unsigned, bool) const NetExpr* PEVoid::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const
{ {
return 0; return 0;
} }

View File

@ -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_DO:
case index_component_t::SEL_IDX_UP: { case index_component_t::SEL_IDX_UP: {
need_constant_expr = true; NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1, true);
NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1);
need_constant_expr = false;
NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex); NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
if (!tmp) { if (!tmp) {
cerr << get_fileline() << ": error: indexed part select of " 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); 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, true);
NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1);
need_constant_expr = false;
NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex); NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
if (!tmp) { if (!tmp) {
cerr << get_fileline() << ": error: array " << sig->name() cerr << get_fileline() << ": error: array " << sig->name()

View File

@ -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 // The initial value for the genvar does not need (nor can it
// use) the genvar itself, so we can evaluate this expression // use) the genvar itself, so we can evaluate this expression
// the same way any other parameter value is evaluated. // the same way any other parameter value is evaluated.
need_constant_expr = true; NetExpr*init_ex = elab_and_eval(des, container, loop_init, -1, true);
NetExpr*init_ex = elab_and_eval(des, container, loop_init, -1);
need_constant_expr = false;
NetEConst*init = dynamic_cast<NetEConst*> (init_ex); NetEConst*init = dynamic_cast<NetEConst*> (init_ex);
if (init == 0) { if (init == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar" 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; cerr << get_fileline() << ": debug: genvar init = " << genvar << endl;
container->genvar_tmp = loop_index; container->genvar_tmp = loop_index;
container->genvar_tmp_val = genvar; container->genvar_tmp_val = genvar;
need_constant_expr = true; NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1, true);
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
need_constant_expr = false;
NetEConst*test = dynamic_cast<NetEConst*>(test_ex); NetEConst*test = dynamic_cast<NetEConst*>(test_ex);
if (test == 0) { if (test == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar" cerr << get_fileline() << ": error: Cannot evaluate genvar"
@ -668,9 +664,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
elaborate_subscope_(des, scope); elaborate_subscope_(des, scope);
// Calculate the step for the loop variable. // Calculate the step for the loop variable.
need_constant_expr = true; NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1, true);
NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1);
need_constant_expr = false;
NetEConst*step = dynamic_cast<NetEConst*>(step_ex); NetEConst*step = dynamic_cast<NetEConst*>(step_ex);
if (step == 0) { if (step == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar" 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) 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, true);
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
need_constant_expr = false;
NetEConst*test = dynamic_cast<NetEConst*> (test_ex); NetEConst*test = dynamic_cast<NetEConst*> (test_ex);
if (test == 0) { if (test == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar" 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) 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, true);
NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1);
need_constant_expr = false;
NetEConst*case_value_co = dynamic_cast<NetEConst*>(case_value_ex); NetEConst*case_value_co = dynamic_cast<NetEConst*>(case_value_ex);
if (case_value_co == 0) { if (case_value_co == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar case" 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; bool match_flag = false;
for (unsigned idx = 0 ; idx < item->item_test.size() && !match_flag ; idx +=1 ) { 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,
NetExpr*item_value_ex = elab_and_eval(des, container, item->item_test[idx], -1); item->item_test[idx],
need_constant_expr = false; -1, true);
NetEConst*item_value_co = dynamic_cast<NetEConst*>(item_value_ex); NetEConst*item_value_co = dynamic_cast<NetEConst*>(item_value_ex);
if (item_value_co == 0) { if (item_value_co == 0) {
cerr << get_fileline() << ": error: Cannot evaluate " 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 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, true) : 0;
NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1) : 0; NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1, true) : 0;
NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1) : 0;
need_constant_expr = false;
NetEConst*msb = dynamic_cast<NetEConst*> (mse); NetEConst*msb = dynamic_cast<NetEConst*> (mse);
NetEConst*lsb = dynamic_cast<NetEConst*> (lse); NetEConst*lsb = dynamic_cast<NetEConst*> (lse);

View File

@ -35,14 +35,6 @@
# include "util.h" # include "util.h"
# include "ivl_assert.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) static bool get_const_argument(NetExpr*exp, verinum&res)
{ {
switch (exp->expr_type()) { switch (exp->expr_type()) {
@ -472,14 +464,14 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
if (return_type_.range) { if (return_type_.range) {
ivl_assert(*this, return_type_.range->size() == 2); ivl_assert(*this, return_type_.range->size() == 2);
need_constant_expr = true;
NetExpr*me = elab_and_eval(des, scope, NetExpr*me = elab_and_eval(des, scope,
return_type_.range->at(0), -1); return_type_.range->at(0), -1,
true);
assert(me); assert(me);
NetExpr*le = elab_and_eval(des, scope, NetExpr*le = elab_and_eval(des, scope,
return_type_.range->at(1), -1); return_type_.range->at(1), -1,
true);
assert(le); assert(le);
need_constant_expr = false;
long mnum = 0, lnum = 0; long mnum = 0, lnum = 0;
if ( ! get_const_argument(me, mnum) ) { 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); ivl_assert(*this, return_type_.range != 0);
long use_wid; long use_wid;
{ {
need_constant_expr = true;
NetExpr*me = elab_and_eval(des, scope, NetExpr*me = elab_and_eval(des, scope,
(*return_type_.range)[0], -1); (*return_type_.range)[0], -1,
true);
assert(me); assert(me);
NetExpr*le = elab_and_eval(des, scope, NetExpr*le = elab_and_eval(des, scope,
(*return_type_.range)[1], -1); (*return_type_.range)[1], -1,
true);
assert(le); assert(le);
need_constant_expr = false;
long mnum = 0, lnum = 0; long mnum = 0, lnum = 0;
if ( ! get_const_argument(me, mnum) ) { 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; bool bad_lsb = false, bad_msb = false;
/* If they exist get the port definition MSB and LSB */ /* If they exist get the port definition MSB and LSB */
if (port_set_ && port_msb_ != 0) { if (port_set_ && port_msb_ != 0) {
/* We do not currently support constant user function. */ NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1, true);
need_constant_expr = true;
NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1);
need_constant_expr = false;
if (! eval_as_long(pmsb, texpr)) { if (! eval_as_long(pmsb, texpr)) {
cerr << port_msb_->get_fileline() << ": error: " cerr << port_msb_->get_fileline() << ": error: "
@ -865,10 +854,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
delete texpr; delete texpr;
/* We do not currently support constant user function. */ texpr = elab_and_eval(des, scope, port_lsb_, -1, true);
need_constant_expr = true;
texpr = elab_and_eval(des, scope, port_lsb_, -1);
need_constant_expr = false;
if (! eval_as_long(plsb, texpr)) { if (! eval_as_long(plsb, texpr)) {
cerr << port_lsb_->get_fileline() << ": error: " 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 they exist get the net/etc. definition MSB and LSB */
if (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) { if (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) {
/* We do not currently support constant user function. */ NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1, true);
need_constant_expr = true;
NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1);
need_constant_expr = false;
if (! eval_as_long(nmsb, texpr)) { if (! eval_as_long(nmsb, texpr)) {
cerr << net_msb_->get_fileline() << ": error: " cerr << net_msb_->get_fileline() << ": error: "
@ -909,10 +892,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
delete texpr; delete texpr;
/* We do not currently support constant user function. */ texpr = elab_and_eval(des, scope, net_lsb_, -1, true);
need_constant_expr = true;
texpr = elab_and_eval(des, scope, net_lsb_, -1);
need_constant_expr = false;
if (! eval_as_long(nlsb, texpr)) { if (! eval_as_long(nlsb, texpr)) {
cerr << net_lsb_->get_fileline() << ": error: " cerr << net_lsb_->get_fileline() << ": error: "
@ -1003,10 +983,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
if (lidx_ || ridx_) { if (lidx_ || ridx_) {
assert(lidx_ && ridx_); assert(lidx_ && ridx_);
need_constant_expr = true; NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1, true);
NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1); NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1, true);
NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1);
need_constant_expr = false;
if ((lexp == 0) || (rexp == 0)) { if ((lexp == 0) || (rexp == 0)) {
cerr << get_fileline() << ": internal error: There is " cerr << get_fileline() << ": internal error: There is "

View File

@ -227,10 +227,8 @@ unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope,
gates, then I am expected to make more than one gates, then I am expected to make more than one
gate. Figure out how many are desired. */ gate. Figure out how many are desired. */
if (msb_) { if (msb_) {
need_constant_expr = true; NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1, true);
NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1); NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1, true);
NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1);
need_constant_expr = false;
NetEConst*msb_con = dynamic_cast<NetEConst*>(msb_exp); NetEConst*msb_con = dynamic_cast<NetEConst*>(msb_exp);
NetEConst*lsb_con = dynamic_cast<NetEConst*>(lsb_exp); NetEConst*lsb_con = dynamic_cast<NetEConst*>(lsb_exp);
@ -2057,9 +2055,8 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
{ {
ivl_assert(*this, rval_); ivl_assert(*this, rval_);
need_constant_expr = is_constant_; NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, lv_width, rval(),
NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, lv_width, rval()); is_constant_);
need_constant_expr = false;
if (!is_constant_ || !rv) return rv; if (!is_constant_ || !rv) return rv;
@ -3376,7 +3373,8 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
PExpr::width_mode_t mode; PExpr::width_mode_t mode;
pe->test_width(des, scope, 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) { if (expr == 0) {
cerr << get_fileline() << ": error: Unable to elaborate" cerr << get_fileline() << ": error: Unable to elaborate"
" wait condition expression." << endl; " wait condition expression." << endl;
@ -4204,9 +4202,8 @@ bool Module::elaborate(Design*des, NetScope*scope) const
for (specparam_it_t cur = specparams.begin() for (specparam_it_t cur = specparams.begin()
; cur != specparams.end() ; ++ cur ) { ; cur != specparams.end() ; ++ cur ) {
need_constant_expr = true; NetExpr*val = elab_and_eval(des, scope, (*cur).second, -1,
NetExpr*val = elab_and_eval(des, scope, (*cur).second, -1); true);
need_constant_expr = false;
NetScope::spec_val_t value; NetScope::spec_val_t value;
if (NetECReal*val_cr = dynamic_cast<NetECReal*> (val)) { if (NetECReal*val_cr = dynamic_cast<NetECReal*> (val)) {

View File

@ -1946,12 +1946,5 @@ NetExpr* NetESFunc::eval_tree()
NetExpr* NetEUFunc::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; return 0;
} }

View File

@ -332,7 +332,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
/* Evaluate the msb expression, if it is present. */ /* Evaluate the msb expression, if it is present. */
PExpr*msb_expr = (*cur).second.msb_expr; PExpr*msb_expr = (*cur).second.msb_expr;
if (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)) { if (! eval_as_long(msb, (*cur).second.msb)) {
cerr << (*cur).second.val->get_fileline() cerr << (*cur).second.val->get_fileline()
<< ": error: Unable to evaluate msb expression " << ": 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. */ /* Evaluate the lsb expression, if it is present. */
PExpr*lsb_expr = (*cur).second.lsb_expr; PExpr*lsb_expr = (*cur).second.lsb_expr;
if (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)) { if (! eval_as_long(lsb, (*cur).second.lsb)) {
cerr << (*cur).second.val->get_fileline() cerr << (*cur).second.val->get_fileline()
<< ": error: Unable to evaluate lsb expression " << ": error: Unable to evaluate lsb expression "
@ -369,7 +369,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
if (range_flag) if (range_flag)
lv_width = (msb >= lsb) ? 1 + msb - lsb : 1 + lsb - msb; 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) if (! expr)
return; return;
@ -488,7 +488,7 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
PExpr*val_expr = (*cur).second.val_expr; PExpr*val_expr = (*cur).second.val_expr;
NetScope*val_scope = (*cur).second.val_scope; 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) if (! expr)
return; return;
@ -631,14 +631,6 @@ void NetScope::evaluate_parameter_(Design*des, param_ref_t cur)
cur->second.val_expr = 0; 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) void NetScope::evaluate_parameters(Design*des)
{ {
for (map<hname_t,NetScope*>::const_iterator cur = children_.begin() for (map<hname_t,NetScope*>::const_iterator cur = children_.begin()
@ -649,13 +641,11 @@ void NetScope::evaluate_parameters(Design*des)
cerr << ":0" << ": debug: " cerr << ":0" << ": debug: "
<< "Evaluate parameters in " << scope_path(this) << endl; << "Evaluate parameters in " << scope_path(this) << endl;
is_param_expr = true;
for (param_ref_t cur = parameters.begin() for (param_ref_t cur = parameters.begin()
; cur != parameters.end() ; ++ cur) { ; cur != parameters.end() ; ++ cur) {
evaluate_parameter_(des, cur); evaluate_parameter_(des, cur);
} }
is_param_expr = false;
} }
void Design::residual_defparams() void Design::residual_defparams()

View File

@ -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; PExpr::width_mode_t mode = PExpr::SIZED;
if ((context_width == -2) && !gn_strict_expr_width_flag) 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; if (tmp == 0) return 0;
eval_expr(tmp, context_width); 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, 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; PExpr::width_mode_t mode = PExpr::SIZED;
pe->test_width(des, scope, mode); 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; << ", 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; if (tmp == 0) return 0;
eval_expr(tmp, -1); eval_expr(tmp, -1);

View File

@ -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); 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 * This function elaborates an expression, and tries to evaluate it
* right away. If the expression can be evaluated, this returns a * right away. If the expression can be evaluated, this returns a
@ -160,14 +149,16 @@ extern bool is_param_expr;
class PExpr; class PExpr;
extern NetExpr* elab_and_eval(Design*des, NetScope*scope, 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 * This function is a variant of elab_and_eval that elaborates and
* evaluates the arguments of a system task. * evaluates the arguments of a system task.
*/ */
extern NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name, extern NetExpr* elab_sys_task_arg(Design*des, NetScope*scope,
unsigned arg_idx, PExpr*pe); 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 * 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 * 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, extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
ivl_variable_type_t lv_type, 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 * This procedure evaluates an expression and if the evaluation is