More expression types work in constant functions.

This commit is contained in:
Stephen Williams 2012-05-29 13:56:16 -07:00
parent def9d0ea1d
commit a5a7050120
3 changed files with 322 additions and 148 deletions

View File

@ -34,11 +34,11 @@ NetExpr* NetExpr::eval_tree()
return 0;
}
static bool get_real_arg_(NetExpr*expr, verireal&val)
static bool get_real_arg_(const NetExpr*expr, verireal&val)
{
switch (expr->expr_type()) {
case IVL_VT_REAL: {
NetECReal*c = dynamic_cast<NetECReal*> (expr);
const NetECReal*c = dynamic_cast<const NetECReal*> (expr);
if (c == 0) return false;
val = c->value();
break;
@ -46,7 +46,7 @@ static bool get_real_arg_(NetExpr*expr, verireal&val)
case IVL_VT_BOOL:
case IVL_VT_LOGIC: {
NetEConst*c = dynamic_cast<NetEConst*>(expr);
const NetEConst*c = dynamic_cast<const NetEConst*>(expr);
if (c == 0) return false;
verinum tmp = c->value();
val = verireal(tmp.as_double());
@ -60,7 +60,7 @@ static bool get_real_arg_(NetExpr*expr, verireal&val)
return true;
}
static bool get_real_arguments(NetExpr*le, NetExpr*re,
static bool get_real_arguments(const NetExpr*le, const NetExpr*re,
double&lval, double&rval)
{
verireal val;
@ -82,15 +82,15 @@ bool NetEBinary::get_real_arguments_(verireal&lval, verireal&rval)
return true;
}
NetECReal* NetEBAdd::eval_tree_real_()
NetECReal* NetEBAdd::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
{
verireal lval;
verireal rval;
double lval;
double rval;
bool flag = get_real_arguments_(lval, rval);
bool flag = get_real_arguments(l, r, lval, rval);
if (!flag) return 0;
verireal res_val;
double res_val;
switch (op()) {
case '+':
@ -103,7 +103,7 @@ NetECReal* NetEBAdd::eval_tree_real_()
ivl_assert(*this, 0);
}
NetECReal*res = new NetECReal( res_val );
NetECReal*res = new NetECReal( verireal(res_val) );
ivl_assert(*this, res);
res->set_line(*this);
@ -119,52 +119,24 @@ NetExpr* NetEBAdd::eval_tree()
eval_expr(left_);
eval_expr(right_);
if (expr_type() == IVL_VT_REAL)
return eval_tree_real_();
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
/* If both operands are constant, then replace the entire
expression with a constant value. */
if (lc != 0 && rc != 0) {
verinum lval = lc->value();
verinum rval = rc->value();
unsigned wid = expr_width();
ivl_assert(*this, wid > 0);
ivl_assert(*this, lval.len() == wid);
ivl_assert(*this, rval.len() == wid);
verinum val;
switch (op_) {
case '+':
val = verinum(lval + rval, wid);
break;
case '-':
val = verinum(lval - rval, wid);
break;
default:
return 0;
}
NetEConst *res = new NetEConst(val);
ivl_assert(*this, res);
res->set_line(*this);
if (debug_eval_tree)
cerr << get_fileline() << ": debug: Evaluated: " << *this
<< " --> " << *res << endl;
// First try to elaborate the expression completely.
NetExpr*res = eval_arguments_(left_,right_);
if (res != 0)
return res;
}
/* Try to combine a right constant value with the right
constant value of a sub-expression add. For example, the
expression (a + 2) - 1 can be rewritten as a + 1. */
// If the expression type is real, then do not attempt the
// following alternative processing.
if (expr_type() == IVL_VT_REAL)
return 0;
// The expression has not evaluated to a constant. Let's still
// try to optimize by trying to combine a right constant value
// with the right constant value of a sub-expression add. For
// example, the expression (a + 2) - 1 can be rewritten as a + 1.
NetEBAdd*se = dynamic_cast<NetEBAdd*>(left_);
lc = se? dynamic_cast<NetEConst*>(se->right_) : 0;
NetEConst*lc = se? dynamic_cast<NetEConst*>(se->right_) : 0;
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
if (lc != 0 && rc != 0) {
ivl_assert(*this, se != 0);
@ -200,11 +172,56 @@ NetExpr* NetEBAdd::eval_tree()
tmp->set_line(*right_);
delete right_;
right_ = tmp;
/* We've changed the subexpression, but the result is
still not constant, so return nil here anyhow. */
return 0;
}
// We may have changed the subexpression, but the result is
// still not constant, so return nil here anyhow.
return 0;
}
NetExpr* NetEBAdd::eval_arguments_(const NetExpr*l, const NetExpr*r) const
{
if (expr_type() == IVL_VT_REAL)
return eval_tree_real_(l,r);
const NetEConst*lc = dynamic_cast<const NetEConst*>(l);
const NetEConst*rc = dynamic_cast<const NetEConst*>(r);
/* If both operands are constant, then replace the entire
expression with a constant value. */
if (lc != 0 && rc != 0) {
verinum lval = lc->value();
verinum rval = rc->value();
unsigned wid = expr_width();
ivl_assert(*this, wid > 0);
ivl_assert(*this, lval.len() == wid);
ivl_assert(*this, rval.len() == wid);
verinum val;
switch (op_) {
case '+':
val = verinum(lval + rval, wid);
break;
case '-':
val = verinum(lval - rval, wid);
break;
default:
return 0;
}
NetEConst *res = new NetEConst(val);
ivl_assert(*this, res);
res->set_line(*this);
if (debug_eval_tree)
cerr << get_fileline() << ": debug: Evaluated: " << *this
<< " --> " << *res << endl;
return res;
}
/* Nothing more to be done, the value is not constant. */
return 0;
}
@ -276,13 +293,12 @@ NetEConst* NetEBBits::eval_tree()
return new NetEConst(res);
}
NetEConst* NetEBComp::eval_less_()
NetEConst* NetEBComp::eval_less_(const NetExpr*le, const NetExpr*re) const
{
if (right_->expr_type() == IVL_VT_REAL ||
left_->expr_type() == IVL_VT_REAL)
return eval_leeq_real_(left_, right_, false);
if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL)
return eval_leeq_real_(le, re, false);
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
const NetEConst*rc = dynamic_cast<const NetEConst*>(re);
if (rc == 0) return 0;
verinum rv = rc->value();
@ -292,12 +308,12 @@ NetEConst* NetEBComp::eval_less_()
return res;
}
if (NetEConst*tmp = must_be_leeq_(left_, rv, false)) {
if (NetEConst*tmp = must_be_leeq_(le, rv, false)) {
return tmp;
}
/* Now go on to the normal test of the values. */
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
const NetEConst*lc = dynamic_cast<const NetEConst*>(le);
if (lc == 0) return 0;
verinum lv = lc->value();
@ -318,7 +334,7 @@ NetEConst* NetEBComp::eval_less_()
}
}
NetEConst* NetEBComp::must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag)
NetEConst* NetEBComp::must_be_leeq_(const NetExpr*le, const verinum&rv, bool eq_flag) const
{
assert(le->expr_width() > 0);
verinum lv (verinum::V1, le->expr_width());
@ -339,7 +355,7 @@ NetEConst* NetEBComp::must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag)
return 0;
}
NetEConst* NetEBComp::eval_leeq_real_(NetExpr*le, NetExpr*re, bool eq_flag)
NetEConst* NetEBComp::eval_leeq_real_(const NetExpr*le, const NetExpr*re, bool eq_flag) const
{
double lval;
double rval;
@ -358,14 +374,13 @@ NetEConst* NetEBComp::eval_leeq_real_(NetExpr*le, NetExpr*re, bool eq_flag)
return res;
}
NetEConst* NetEBComp::eval_leeq_()
NetEConst* NetEBComp::eval_leeq_(const NetExpr*le, const NetExpr*re) const
{
if (right_->expr_type() == IVL_VT_REAL ||
left_->expr_type() == IVL_VT_REAL)
return eval_leeq_real_(left_, right_, true);
if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL)
return eval_leeq_real_(le, re, true);
// assert(expr_type() == IVL_VT_LOGIC);
NetEConst*r = dynamic_cast<NetEConst*>(right_);
const NetEConst*r = dynamic_cast<const NetEConst*>(re);
if (r == 0) return 0;
verinum rv = r->value();
@ -375,18 +390,18 @@ NetEConst* NetEBComp::eval_leeq_()
return res;
}
if (left_->expr_width() == 0) {
if (le->expr_width() == 0) {
cerr << get_fileline() << ": internal error: Something wrong "
<< "with the left side width of <= ?" << endl;
cerr << get_fileline() << ": : " << *this << endl;
}
if (NetEConst*tmp = must_be_leeq_(left_, rv, true)) {
if (NetEConst*tmp = must_be_leeq_(le, rv, true)) {
return tmp;
}
/* Now go on to the normal test of the values. */
NetEConst*l = dynamic_cast<NetEConst*>(left_);
const NetEConst*l = dynamic_cast<const NetEConst*>(le);
if (l == 0) return 0;
verinum lv = l->value();
@ -407,13 +422,12 @@ NetEConst* NetEBComp::eval_leeq_()
}
}
NetEConst* NetEBComp::eval_gt_()
NetEConst* NetEBComp::eval_gt_(const NetExpr*le, const NetExpr*re) const
{
if (right_->expr_type() == IVL_VT_REAL ||
left_->expr_type() == IVL_VT_REAL)
return eval_leeq_real_(right_, left_, false);
if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL)
return eval_leeq_real_(re, le, false);
NetEConst*l = dynamic_cast<NetEConst*>(left_);
const NetEConst*l = dynamic_cast<const NetEConst*>(le);
if (l == 0) return 0;
verinum lv = l->value();
@ -423,12 +437,12 @@ NetEConst* NetEBComp::eval_gt_()
return res;
}
if (NetEConst*tmp = must_be_leeq_(right_, lv, false)) {
if (NetEConst*tmp = must_be_leeq_(re, lv, false)) {
return tmp;
}
/* Now go on to the normal test of the values. */
NetEConst*r = dynamic_cast<NetEConst*>(right_);
const NetEConst*r = dynamic_cast<const NetEConst*>(re);
if (r == 0) return 0;
verinum rv = r->value();
@ -449,13 +463,12 @@ NetEConst* NetEBComp::eval_gt_()
}
}
NetEConst* NetEBComp::eval_gteq_()
NetEConst* NetEBComp::eval_gteq_(const NetExpr*le, const NetExpr*re) const
{
if (right_->expr_type() == IVL_VT_REAL ||
left_->expr_type() == IVL_VT_REAL)
return eval_leeq_real_(right_, left_, true);
if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL)
return eval_leeq_real_(re, le, true);
NetEConst*l = dynamic_cast<NetEConst*>(left_);
const NetEConst*l = dynamic_cast<const NetEConst*>(left_);
if (l == 0) return 0;
verinum lv = l->value();
@ -465,12 +478,12 @@ NetEConst* NetEBComp::eval_gteq_()
return res;
}
if (NetEConst*tmp = must_be_leeq_(right_, lv, true)) {
if (NetEConst*tmp = must_be_leeq_(re, lv, true)) {
return tmp;
}
/* Now go on to the normal test of the values. */
NetEConst*r = dynamic_cast<NetEConst*>(right_);
const NetEConst*r = dynamic_cast<const NetEConst*>(re);
if (r == 0) return 0;
verinum rv = r->value();
@ -498,15 +511,15 @@ NetEConst* NetEBComp::eval_gteq_()
* are equal, but there are are x/z bits, then the situation is
* ambiguous so the result is x.
*/
NetEConst* NetEBComp::eval_eqeq_real_(bool ne_flag)
NetEConst* NetEBComp::eval_eqeq_real_(bool ne_flag, const NetExpr*le, const NetExpr*re) const
{
verireal lval;
verireal rval;
double lval;
double rval;
bool flag = get_real_arguments_(lval, rval);
bool flag = get_real_arguments(le, re, lval, rval);
if (! flag) return 0;
verinum result(((lval.as_double() == rval.as_double()) ^ ne_flag) ?
verinum result(((lval == rval) ^ ne_flag) ?
verinum::V1 : verinum::V0, 1);
NetEConst*res = new NetEConst(result);
ivl_assert(*this, res);
@ -514,14 +527,14 @@ NetEConst* NetEBComp::eval_eqeq_real_(bool ne_flag)
return res;
}
NetEConst* NetEBComp::eval_eqeq_(bool ne_flag)
NetEConst* NetEBComp::eval_eqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const
{
if (left_->expr_type() == IVL_VT_REAL ||
right_->expr_type() == IVL_VT_REAL)
return eval_eqeq_real_(ne_flag);
if (le->expr_type() == IVL_VT_REAL ||
re->expr_type() == IVL_VT_REAL)
return eval_eqeq_real_(ne_flag, le, re);
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
const NetEConst*lc = dynamic_cast<const NetEConst*>(le);
const NetEConst*rc = dynamic_cast<const NetEConst*>(re);
if (lc == 0 || rc == 0) return 0;
const verinum&lv = lc->value();
@ -631,10 +644,10 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag)
return result;
}
NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag)
NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const
{
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
const NetEConst*lc = dynamic_cast<const NetEConst*>(le);
const NetEConst*rc = dynamic_cast<const NetEConst*>(re);
if (lc == 0 || rc == 0) return 0;
const verinum&lv = lc->value();
@ -687,47 +700,54 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag)
return result;
}
NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const
{
NetEConst*res = 0;
switch (op_) {
case 'E': // Case equality (===)
res = eval_eqeqeq_(false, l, r);
break;
case 'e': // Equality (==)
res = eval_eqeq_(false, l, r);
break;
case 'G': // >=
res = eval_gteq_(l, r);
break;
case 'L': // <=
res = eval_leeq_(l, r);
break;
case 'N': // Case inequality (!==)
res = eval_eqeqeq_(true, l, r);
break;
case 'n': // not-equal (!=)
res = eval_eqeq_(true, l, r);
break;
case '<': // Less than
res = eval_less_(l, r);
break;
case '>': // Greater than
res = eval_gt_(l, r);
break;
}
return res;
}
NetEConst* NetEBComp::eval_tree()
{
eval_expr(left_);
eval_expr(right_);
NetEConst*res = 0;
switch (op_) {
case 'E': // Case equality (===)
res = eval_eqeqeq_(false);
break;
case 'e': // Equality (==)
res = eval_eqeq_(false);
break;
case 'G': // >=
res = eval_gteq_();
break;
case 'L': // <=
res = eval_leeq_();
break;
case 'N': // Case inequality (!==)
res = eval_eqeqeq_(true);
break;
case 'n': // not-equal (!=)
res = eval_eqeq_(true);
break;
case '<': // Less than
res = eval_less_();
break;
case '>': // Greater than
res = eval_gt_();
break;
}
NetEConst*res = eval_arguments_(left_, right_);
if (res == 0) return 0;
res->set_line(*this);
@ -1043,9 +1063,13 @@ NetEConst* NetEBShift::eval_tree()
{
eval_expr(left_);
eval_expr(right_);
return eval_arguments_(left_,right_);
}
NetEConst*le = dynamic_cast<NetEConst*>(left_);
NetEConst*re = dynamic_cast<NetEConst*>(right_);
NetEConst* NetEBShift::eval_arguments_(const NetExpr*l, const NetExpr*r) const
{
const NetEConst*le = dynamic_cast<const NetEConst*>(l);
const NetEConst*re = dynamic_cast<const NetEConst*>(r);
if (le == 0 || re == 0) return 0;
NetEConst*res;

View File

@ -18,6 +18,7 @@
*/
# include "netlist.h"
# include "compiler.h"
# include <typeinfo>
# include "ivl_assert.h"
@ -29,6 +30,11 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
map<perm_string,NetExpr*>::iterator ptr;
map<perm_string,NetExpr*>context_map;
if (debug_eval_tree) {
cerr << loc.get_fileline() << ": debug: "
<< "Evaluate function " << scope_->basename() << endl;
}
// Put the return value into the map...
context_map[scope_->basename()] = 0;
// Load the input ports into the map...
@ -37,6 +43,11 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
NetExpr*tmp = args[idx]->dup_expr();
perm_string aname = ports_[idx]->name();
context_map[aname] = tmp;
if (debug_eval_tree) {
cerr << loc.get_fileline() << ": debug: "
<< " input " << aname << " = " << *tmp << endl;
}
}
// Perform the evaluation
@ -100,6 +111,13 @@ bool NetAssign::evaluate_function(const LineInfo&loc,
map<perm_string,NetExpr*>::iterator ptr = context_map.find(lval->name());
if (ptr->second)
delete ptr->second;
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: "
<< "NetAssign::evaluate_function: " << lval->name()
<< " = " << *rval_result << endl;
}
ptr->second = rval_result;
return true;
@ -123,6 +141,103 @@ bool NetBlock::evaluate_function(const LineInfo&loc,
return flag;
}
bool NetWhile::evaluate_function(const LineInfo&loc,
map<perm_string,NetExpr*>&context_map) const
{
bool flag = true;
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: NetWhile::evaluate_fuction: "
<< "Start loop" << endl;
}
while (flag) {
// Evaluate the condition expression to try and get the
// condition for the loop.
NetExpr*cond = cond_->evaluate_function(loc, context_map);
if (cond == 0) {
flag = false;
break;
}
NetEConst*cond_const = dynamic_cast<NetEConst*> (cond);
ivl_assert(loc, cond_const);
long val = cond_const->value().as_long();
delete cond;
// If the condition is false, then break.
if (val == 0)
break;
// The condition is true, so evalutate the statement
// another time.
bool tmp_flag = proc_->evaluate_function(loc, context_map);
if (! tmp_flag)
flag = false;
}
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: NetWhile::evaluate_fuction: "
<< "Done loop" << endl;
}
return flag;
}
NetExpr* NetEBComp::evaluate_function(const LineInfo&loc,
map<perm_string,NetExpr*>&context_map) const
{
NetExpr*lval = left_->evaluate_function(loc, context_map);
NetExpr*rval = right_->evaluate_function(loc, context_map);
if (lval == 0 || rval == 0) {
delete lval;
delete rval;
return 0;
}
NetEConst*res = eval_arguments_(lval, rval);
delete lval;
delete rval;
return res;
}
NetExpr* NetEBAdd::evaluate_function(const LineInfo&loc,
map<perm_string,NetExpr*>&context_map) const
{
NetExpr*lval = left_->evaluate_function(loc, context_map);
NetExpr*rval = right_->evaluate_function(loc, context_map);
if (lval == 0 || rval == 0) {
delete lval;
delete rval;
return 0;
}
NetExpr*res = eval_arguments_(lval, rval);
delete lval;
delete rval;
return res;
}
NetExpr* NetEBShift::evaluate_function(const LineInfo&loc,
map<perm_string,NetExpr*>&context_map) const
{
NetExpr*lval = left_->evaluate_function(loc, context_map);
NetExpr*rval = right_->evaluate_function(loc, context_map);
if (lval == 0 || rval == 0) {
delete lval;
delete rval;
return 0;
}
NetEConst*res = eval_arguments_(lval, rval);
delete lval;
delete rval;
return res;
}
NetExpr* NetEConst::evaluate_function(const LineInfo&,
map<perm_string,NetExpr*>&) const
@ -131,3 +246,21 @@ NetExpr* NetEConst::evaluate_function(const LineInfo&,
res->set_line(*this);
return res;
}
NetExpr* NetESignal::evaluate_function(const LineInfo&,
map<perm_string,NetExpr*>&context_map) const
{
if (word_) {
cerr << get_fileline() << ": sorry: I don't know how to evaluate signal word selects at compile time." << endl;
return 0;
}
map<perm_string,NetExpr*>::iterator ptr = context_map.find(name());
if (ptr == context_map.end()) {
cerr << get_fileline() << ": error: Cannot evaluate " << name()
<< " in this context." << endl;
return 0;
}
return ptr->second->dup_expr();
}

View File

@ -3294,6 +3294,8 @@ class NetWhile : public NetProc {
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,NetExpr*>&ctx) const;
private:
NetExpr* cond_;
@ -3451,10 +3453,14 @@ class NetEBAdd : public NetEBinary {
virtual NetEBAdd* dup_expr() const;
virtual NetExpr* eval_tree();
virtual NetExpr* evaluate_function(const LineInfo&loc,
std::map<perm_string,NetExpr*>&ctx) const;
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private:
NetECReal* eval_tree_real_();
NetExpr * eval_arguments_(const NetExpr*l, const NetExpr*r) const;
NetECReal* eval_tree_real_(const NetExpr*l, const NetExpr*r) const;
};
/*
@ -3530,19 +3536,23 @@ class NetEBComp : public NetEBinary {
virtual NetEBComp* dup_expr() const;
virtual NetEConst* eval_tree();
virtual NetExpr*evaluate_function(const LineInfo&loc,
std::map<perm_string,NetExpr*>&ctx) const;
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private:
NetEConst* must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag);
NetEConst* must_be_leeq_(const NetExpr*le, const verinum&rv, bool eq_flag) const;
NetEConst*eval_eqeq_(bool ne_flag);
NetEConst*eval_eqeq_real_(bool ne_flag);
NetEConst*eval_less_();
NetEConst*eval_leeq_();
NetEConst*eval_leeq_real_(NetExpr*le, NetExpr*ri, bool eq_flag);
NetEConst*eval_gt_();
NetEConst*eval_gteq_();
NetEConst*eval_eqeqeq_(bool ne_flag);
NetEConst*eval_arguments_(const NetExpr*le, const NetExpr*re) const;
NetEConst*eval_eqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const;
NetEConst*eval_eqeq_real_(bool ne_flag, const NetExpr*le, const NetExpr*re) const;
NetEConst*eval_less_(const NetExpr*le, const NetExpr*re) const;
NetEConst*eval_leeq_(const NetExpr*le, const NetExpr*re) const;
NetEConst*eval_leeq_real_(const NetExpr*le, const NetExpr*ri, bool eq_flag) const;
NetEConst*eval_gt_(const NetExpr*le, const NetExpr*re) const;
NetEConst*eval_gteq_(const NetExpr*le, const NetExpr*re) const;
NetEConst*eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const;
};
/*
@ -3644,9 +3654,13 @@ class NetEBShift : public NetEBinary {
virtual NetEBShift* dup_expr() const;
virtual NetEConst* eval_tree();
virtual NetExpr*evaluate_function(const LineInfo&loc,
std::map<perm_string,NetExpr*>&ctx) const;
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private:
NetEConst* eval_arguments_(const NetExpr*l, const NetExpr*r) const;
};
@ -3978,6 +3992,9 @@ class NetESignal : public NetExpr {
NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root);
NexusSet* nex_input(bool rem_out = true);
virtual NetExpr*evaluate_function(const LineInfo&loc,
std::map<perm_string,NetExpr*>&ctx) const;
// This is the expression for selecting an array word, if this
// signal refers to an array.
const NetExpr* word_index() const;