Add support for all binary operators in constant user functions.

This patch implements the evaluate_function method for the NetEBBits,
NetEBDiv, NetEBLogic, NetEBMinMax, and NetEBPow classes. It also
factors out some common code into the NetEBinary class.
This commit is contained in:
Martin Whitaker 2013-02-03 09:32:49 +00:00 committed by Cary R
parent 838f6ce862
commit 11f479e028
3 changed files with 166 additions and 120 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -77,12 +77,10 @@ static bool get_real_arguments(const NetExpr*le, const NetExpr*re,
return true; return true;
} }
bool NetEBinary::get_real_arguments_(verireal&lval, verireal&rval) NetExpr* NetEBinary::eval_arguments_(const NetExpr*, const NetExpr*) const
{ {
if (!get_real_arg_(left_, lval)) return false; ivl_assert(*this, 0);
if (!get_real_arg_(right_, rval)) return false; return 0;
return true;
} }
NetECReal* NetEBAdd::eval_tree_real_(const NetExpr*l, const NetExpr*r) const NetECReal* NetEBAdd::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
@ -231,16 +229,16 @@ NetExpr* NetEBAdd::eval_arguments_(const NetExpr*l, const NetExpr*r) const
NetEConst* NetEBBits::eval_tree() NetEConst* NetEBBits::eval_tree()
{ {
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluating expression:"
<< *this << endl;
}
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
NetEConst*lc = dynamic_cast<NetEConst*>(left_); return eval_arguments_(left_, right_);
NetEConst*rc = dynamic_cast<NetEConst*>(right_); }
NetEConst* NetEBBits::eval_arguments_(const NetExpr*l, const NetExpr*r) const
{
const NetEConst*lc = dynamic_cast<const NetEConst*>(l);
const NetEConst*rc = dynamic_cast<const NetEConst*>(r);
if (lc == 0 || rc == 0) return 0; if (lc == 0 || rc == 0) return 0;
/* Notice the special case where one of the operands is 0 and /* Notice the special case where one of the operands is 0 and
@ -293,7 +291,15 @@ NetEConst* NetEBBits::eval_tree()
return 0; return 0;
} }
return new NetEConst(res); NetEConst*tmp = new NetEConst(res);
ivl_assert(*this, tmp);
tmp->set_line(*this);
if (debug_eval_tree)
cerr << get_fileline() << ": debug: Evaluated: " << *this
<< " --> " << *tmp << endl;
return tmp;
} }
NetEConst* NetEBComp::eval_less_(const NetExpr*le, const NetExpr*re) const NetEConst* NetEBComp::eval_less_(const NetExpr*le, const NetExpr*re) const
@ -764,27 +770,28 @@ NetEConst* NetEBComp::eval_tree()
return res; return res;
} }
NetExpr* NetEBDiv::eval_tree_real_() NetExpr* NetEBDiv::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
{ {
verireal lval; double lval;
verireal rval; double rval;
bool flag = get_real_arguments_(lval, rval); bool flag = get_real_arguments(l, r, lval, rval);
if (! flag) return 0; if (! flag) return 0;
NetECReal*res = 0; double res_val = 0.0;
switch (op_) { switch (op_) {
case '/': case '/':
res = new NetECReal(lval / rval); res_val = lval / rval;
break; break;
case '%': case '%':
// Since this could/may be called early we don't want to // Since this could/may be called early we don't want to
// leak functionality. // leak functionality.
if (!gn_icarus_misc_flag) return 0; if (!gn_icarus_misc_flag) return 0;
res = new NetECReal(lval % rval); res_val = fmod(lval, rval);
break; break;
} }
NetECReal*res = new NetECReal( verireal(res_val) );
ivl_assert(*this, res); ivl_assert(*this, res);
res->set_line(*this); res->set_line(*this);
@ -804,11 +811,16 @@ NetExpr* NetEBDiv::eval_tree()
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); return eval_arguments_(left_, right_);
}
NetExpr* NetEBDiv::eval_arguments_(const NetExpr*l, const NetExpr*r) const
{
if (expr_type() == IVL_VT_REAL) return eval_tree_real_(l,r);
assert(expr_type() == IVL_VT_LOGIC); assert(expr_type() == IVL_VT_LOGIC);
NetEConst*lc = dynamic_cast<NetEConst*>(left_); const NetEConst*lc = dynamic_cast<const NetEConst*>(l);
NetEConst*rc = dynamic_cast<NetEConst*>(right_); const NetEConst*rc = dynamic_cast<const NetEConst*>(r);
if (lc == 0 || rc == 0) return 0; if (lc == 0 || rc == 0) return 0;
verinum lval = lc->value(); verinum lval = lc->value();
@ -841,25 +853,25 @@ NetExpr* NetEBDiv::eval_tree()
return tmp; return tmp;
} }
NetEConst* NetEBLogic::eval_tree_real_() NetEConst* NetEBLogic::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
{ {
verireal lval; double lval;
verireal rval; double rval;
bool flag = get_real_arguments_(lval, rval); bool flag = get_real_arguments(l, r, lval, rval);
if (! flag) return 0; if (! flag) return 0;
verinum::V res; verinum::V res;
switch (op_) { switch (op_) {
case 'a': // Logical AND (&&) case 'a': // Logical AND (&&)
if ((lval.as_double() != 0.0) && (rval.as_double() != 0.0)) if ((lval != 0.0) && (rval != 0.0))
res = verinum::V1; res = verinum::V1;
else else
res = verinum::V0; res = verinum::V0;
break; break;
case 'o': // Logical OR (||) case 'o': // Logical OR (||)
if ((lval.as_double() != 0.0) || (rval.as_double() != 0.0)) if ((lval != 0.0) || (rval != 0.0))
res = verinum::V1; res = verinum::V1;
else else
res = verinum::V0; res = verinum::V0;
@ -885,13 +897,17 @@ NetEConst* NetEBLogic::eval_tree()
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
if (left_->expr_type() == IVL_VT_REAL || return eval_arguments_(left_, right_);
right_->expr_type() == IVL_VT_REAL) }
return eval_tree_real_();
NetEConst* NetEBLogic::eval_arguments_(const NetExpr*l, const NetExpr*r) const
{
if (l->expr_type() == IVL_VT_REAL || r->expr_type() == IVL_VT_REAL)
return eval_tree_real_(l,r);
assert(expr_type() == IVL_VT_LOGIC); assert(expr_type() == IVL_VT_LOGIC);
NetEConst*lc = dynamic_cast<NetEConst*>(left_); const NetEConst*lc = dynamic_cast<const NetEConst*>(l);
NetEConst*rc = dynamic_cast<NetEConst*>(right_); const NetEConst*rc = dynamic_cast<const NetEConst*>(r);
if (lc == 0 || rc == 0) return 0; if (lc == 0 || rc == 0) return 0;
verinum::V lv = verinum::V0; verinum::V lv = verinum::V0;
@ -956,6 +972,87 @@ NetEConst* NetEBLogic::eval_tree()
return tmp; return tmp;
} }
NetExpr* NetEBMinMax::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
{
double lval;
double rval;
bool flag = get_real_arguments(l, r, lval, rval);
if (! flag) return 0;
double res_val;
switch (op()) {
case 'm':
res_val = lval < rval ? lval : rval;
break;
case 'M':
res_val = lval > rval ? lval : rval;
break;
default:
ivl_assert(*this, 0);
}
NetECReal*res = new NetECReal( verireal(res_val) );
ivl_assert(*this, res);
res->set_line(*this);
if (debug_eval_tree)
cerr << get_fileline() << ": debug: Evaluated (real): " << *this
<< " --> " << *res << endl;
return res;
}
NetExpr* NetEBMinMax::eval_tree()
{
eval_expr(left_);
eval_expr(right_);
return eval_arguments_(left_, right_);
}
NetExpr* NetEBMinMax::eval_arguments_(const NetExpr*l, const NetExpr*r) const
{
if (expr_type() == IVL_VT_REAL) return eval_tree_real_(l,r);
assert(expr_type() == IVL_VT_LOGIC);
const NetEConst*lc = dynamic_cast<const NetEConst*>(l);
const NetEConst*rc = dynamic_cast<const NetEConst*>(r);
if (lc == 0 || rc == 0) return 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 res_val;
if (lval.is_defined() && rval.is_defined()) {
switch (op()) {
case 'm':
res_val = lval < rval ? lval : rval;
break;
case 'M':
res_val = lval > rval ? lval : rval;
break;
default:
ivl_assert(*this, 0);
}
} else {
res_val = verinum(verinum::Vx, wid);
}
NetEConst*res = new NetEConst(res_val);
ivl_assert(*this, res);
res->set_line(*this);
if (debug_eval_tree)
cerr << get_fileline() << ": debug: Evaluated: " << *this
<< " --> " << *res << endl;
return res;
}
NetExpr* NetEBMult::eval_tree_real_(const NetExpr*l, const NetExpr*r) const NetExpr* NetEBMult::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
{ {
@ -1013,15 +1110,15 @@ NetExpr* NetEBMult::eval_arguments_(const NetExpr*l, const NetExpr*r) const
return tmp; return tmp;
} }
NetExpr* NetEBPow::eval_tree_real_() NetExpr* NetEBPow::eval_tree_real_(const NetExpr*l, const NetExpr*r) const
{ {
verireal lval; double lval;
verireal rval; double rval;
bool flag = get_real_arguments_(lval, rval); bool flag = get_real_arguments(l, r, lval, rval);
if (! flag) return 0; if (! flag) return 0;
NetECReal*res = new NetECReal( pow(lval,rval) ); NetECReal*res = new NetECReal( verireal( pow(lval,rval) ) );
ivl_assert(*this, res); ivl_assert(*this, res);
res->set_line(*this); res->set_line(*this);
@ -1037,11 +1134,16 @@ NetExpr* NetEBPow::eval_tree()
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); return eval_arguments_(left_, right_);
}
NetExpr* NetEBPow::eval_arguments_(const NetExpr*l, const NetExpr*r) const
{
if (expr_type() == IVL_VT_REAL) return eval_tree_real_(l,r);
assert(expr_type() == IVL_VT_LOGIC); assert(expr_type() == IVL_VT_LOGIC);
NetEConst*lc = dynamic_cast<NetEConst*>(left_); const NetEConst*lc = dynamic_cast<const NetEConst*>(l);
NetEConst*rc = dynamic_cast<NetEConst*>(right_); const NetEConst*rc = dynamic_cast<const NetEConst*>(r);
if (lc == 0 || rc == 0) return 0; if (lc == 0 || rc == 0) return 0;
verinum lval = lc->value(); verinum lval = lc->value();
@ -1071,6 +1173,7 @@ NetEConst* NetEBShift::eval_tree()
{ {
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
return eval_arguments_(left_,right_); return eval_arguments_(left_,right_);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012 Stephen Williams (steve@icarus.com) * Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -267,26 +267,8 @@ bool NetWhile::evaluate_function(const LineInfo&loc,
return flag; return flag;
} }
NetExpr* NetEBComp::evaluate_function(const LineInfo&loc, NetExpr* NetEBinary::evaluate_function(const LineInfo&loc,
map<perm_string,NetExpr*>&context_map) const 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*lval = left_->evaluate_function(loc, context_map);
NetExpr*rval = right_->evaluate_function(loc, context_map); NetExpr*rval = right_->evaluate_function(loc, context_map);
@ -303,42 +285,6 @@ NetExpr* NetEBAdd::evaluate_function(const LineInfo&loc,
return res; return res;
} }
NetExpr* NetEBMult::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&, NetExpr* NetEConst::evaluate_function(const LineInfo&,
map<perm_string,NetExpr*>&) const map<perm_string,NetExpr*>&) const
{ {

View File

@ -3527,6 +3527,8 @@ class NetEBinary : public NetExpr {
virtual bool has_width() const; virtual bool has_width() const;
virtual NetEBinary* dup_expr() const; virtual NetEBinary* dup_expr() const;
virtual NetExpr* evaluate_function(const LineInfo&loc,
std::map<perm_string,NetExpr*>&ctx) const;
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
@ -3537,7 +3539,7 @@ class NetEBinary : public NetExpr {
NetExpr* left_; NetExpr* left_;
NetExpr* right_; NetExpr* right_;
bool get_real_arguments_(verireal&lv, verireal&rv); virtual NetExpr* eval_arguments_(const NetExpr*l, const NetExpr*r) const;
}; };
/* /*
@ -3557,9 +3559,6 @@ class NetEBAdd : public NetEBinary {
virtual NetEBAdd* dup_expr() const; virtual NetEBAdd* dup_expr() const;
virtual NetExpr* eval_tree(); 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); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private:
@ -3585,7 +3584,8 @@ class NetEBDiv : public NetEBinary {
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private:
NetExpr* eval_tree_real_(); NetExpr* eval_arguments_(const NetExpr*l, const NetExpr*r) const;
NetExpr* eval_tree_real_(const NetExpr*l, const NetExpr*r) const;
}; };
/* /*
@ -3610,8 +3610,10 @@ class NetEBBits : public NetEBinary {
virtual NetEBBits* dup_expr() const; virtual NetEBBits* dup_expr() const;
virtual NetEConst* eval_tree(); virtual NetEConst* eval_tree();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private:
NetEConst* eval_arguments_(const NetExpr*l, const NetExpr*r) const;
}; };
/* /*
@ -3639,10 +3641,6 @@ class NetEBComp : public NetEBinary {
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual NetEBComp* dup_expr() const; virtual NetEBComp* dup_expr() const;
virtual NetEConst* eval_tree(); 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); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private:
@ -3677,7 +3675,8 @@ class NetEBLogic : public NetEBinary {
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private:
NetEConst* eval_tree_real_(); NetEConst* eval_arguments_(const NetExpr*l, const NetExpr*r) const;
NetEConst* eval_tree_real_(const NetExpr*l, const NetExpr*r) const;
}; };
/* /*
@ -3695,7 +3694,11 @@ class NetEBMinMax : public NetEBinary {
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual NetExpr* eval_tree();
private: private:
NetExpr* eval_arguments_(const NetExpr*l, const NetExpr*r) const;
NetExpr* eval_tree_real_(const NetExpr*l, const NetExpr*r) const;
}; };
/* /*
@ -3711,8 +3714,6 @@ class NetEBMult : public NetEBinary {
virtual NetEBMult* dup_expr() const; virtual NetEBMult* dup_expr() const;
virtual NetExpr* eval_tree(); 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); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private:
@ -3736,13 +3737,13 @@ class NetEBPow : public NetEBinary {
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private:
NetExpr* eval_tree_real_(); NetExpr* eval_arguments_(const NetExpr*l, const NetExpr*r) const;
NetExpr* eval_tree_real_(const NetExpr*l, const NetExpr*r) const;
}; };
/* /*
* The binary logical operators are those that return boolean * Support the binary shift operators. The supported operators are:
* results. The supported operators are:
* *
* l -- left shift (<<) * l -- left shift (<<)
* r -- right shift (>>) * r -- right shift (>>)
@ -3760,10 +3761,6 @@ class NetEBShift : public NetEBinary {
virtual NetEBShift* dup_expr() const; virtual NetEBShift* dup_expr() const;
virtual NetEConst* eval_tree(); 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); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private: