More eval_tree rework and add support for ! of a real.

This commit is contained in:
Cary R 2010-11-04 10:45:01 -07:00 committed by Stephen Williams
parent ccf01cc665
commit ab8557eaf0
3 changed files with 157 additions and 109 deletions

View File

@ -1325,6 +1325,9 @@ void NetEBinary::dump(ostream&o) const
case 'a': case 'a':
o << "&&"; o << "&&";
break; break;
case 'A':
o << "~&";
break;
case 'E': case 'E':
o << "==="; o << "===";
break; break;
@ -1498,12 +1501,18 @@ void NetEUFunc::dump(ostream&o) const
void NetEUnary::dump(ostream&o) const void NetEUnary::dump(ostream&o) const
{ {
switch (op_) { switch (op_) {
case 'A':
o << "~&";
break;
case 'm': case 'm':
o << "abs"; o << "abs";
break; break;
case 'N': case 'N':
o << "~|"; o << "~|";
break; break;
case 'X':
o << "~^";
break;
default: default:
o << op_; o << op_;
break; break;

View File

@ -899,21 +899,19 @@ NetEConst* NetEBLogic::eval_tree_real_()
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.as_double() != 0.0) && (rval.as_double() != 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.as_double() != 0.0) || (rval.as_double() != 0.0))
res = verinum::V1; res = verinum::V1;
else else
res = verinum::V0; res = verinum::V0;
break; break;
}
default: default:
return 0; return 0;
@ -967,7 +965,7 @@ NetEConst* NetEBLogic::eval_tree(int)
verinum::V res; verinum::V res;
switch (op_) { switch (op_) {
case 'a': { // Logical AND (&&) case 'a': // Logical AND (&&)
if ((lv == verinum::V0) || (rv == verinum::V0)) if ((lv == verinum::V0) || (rv == verinum::V0))
res = verinum::V0; res = verinum::V0;
@ -978,9 +976,8 @@ NetEConst* NetEBLogic::eval_tree(int)
res = verinum::Vx; res = verinum::Vx;
break; break;
}
case 'o': { // Logical OR (||) case 'o': // Logical OR (||)
if ((lv == verinum::V1) || (rv == verinum::V1)) if ((lv == verinum::V1) || (rv == verinum::V1))
res = verinum::V1; res = verinum::V1;
@ -991,7 +988,6 @@ NetEConst* NetEBLogic::eval_tree(int)
res = verinum::Vx; res = verinum::Vx;
break; break;
}
default: default:
return 0; return 0;
@ -1612,26 +1608,29 @@ NetExpr* NetEUnary::eval_tree_real_()
switch (op_) { switch (op_) {
case '+': case '+':
res = new NetECReal(val->value()); res = new NetECReal(val->value());
res->set_line(*this); ivl_assert(*this, res);
return res; break;
case '-': case '-':
res = new NetECReal(-(val->value())); res = new NetECReal(-(val->value()));
res->set_line(*this); ivl_assert(*this, res);
return res; break;
default: default:
return 0; return 0;
} }
res->set_line(*this);
if (debug_eval_tree)
cerr << get_fileline() << ": debug: Evaluated (real): " << *this
<< " --> " << *res << endl;
return res;
} }
NetExpr* NetEUnary::eval_tree(int prune_to_width) NetExpr* NetEUnary::eval_tree(int prune_to_width)
{ {
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluating expression:"
<< *this << ", prune_to_width=" << prune_to_width << endl;
}
eval_expr(expr_); eval_expr(expr_);
if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
@ -1644,24 +1643,20 @@ NetExpr* NetEUnary::eval_tree(int prune_to_width)
case '+': case '+':
/* Unary + is a no-op. */ /* Unary + is a no-op. */
return new NetEConst(val); break;
case '-': { case '-':
if (val.is_defined()) { if (val.is_defined()) {
verinum tmp (verinum::V0, val.len()); verinum tmp (verinum::V0, val.len());
tmp.has_sign(val.has_sign()); tmp.has_sign(val.has_sign());
val = tmp - val; val = tmp - val;
} else { } else {
for (unsigned idx = 0 ; idx < val.len() ; idx += 1) for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
val.set(idx, verinum::Vx); val.set(idx, verinum::Vx);
} }
break;
return new NetEConst(val); case '~':
}
case '~': {
/* Bitwise not is even simpler then logical /* Bitwise not is even simpler then logical
not. Just invert all the bits of the operand and not. Just invert all the bits of the operand and
make the new value with the same dimensions. */ make the new value with the same dimensions. */
@ -1677,14 +1672,23 @@ NetExpr* NetEUnary::eval_tree(int prune_to_width)
val.set(idx, verinum::Vx); val.set(idx, verinum::Vx);
} }
return new NetEConst(val); break;
}
case '!': case '!':
assert(0); assert(0);
default: default:
return 0; 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;
} }
@ -1693,18 +1697,37 @@ NetExpr* NetEUBits::eval_tree(int prune_to_width)
return NetEUnary::eval_tree(prune_to_width); return NetEUnary::eval_tree(prune_to_width);
} }
NetEConst* NetEUReduce::eval_tree(int prune_to_width) NetEConst* NetEUReduce::eval_tree_real_()
{ {
if (debug_eval_tree) { ivl_assert(*this, op_ == '!');
cerr << get_fileline() << ": debug: Evaluating expression:"
<< *this << ", prune_to_width=" << prune_to_width << endl; NetECReal*val= dynamic_cast<NetECReal*> (expr_);
if (val == 0) return 0;
verinum::V res = val->value().as_double() == 0.0 ? verinum::V1 :
verinum::V0;
NetEConst*tmp = new NetEConst(verinum(res, 1));
ivl_assert(*this, tmp);
tmp->set_line(*this);
if (debug_eval_tree)
cerr << get_fileline() << ": debug: Evaluated (real): " << *this
<< " --> " << *tmp << endl;
return tmp;
} }
NetEConst* NetEUReduce::eval_tree(int)
{
eval_expr(expr_); eval_expr(expr_);
if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
NetEConst*rval = dynamic_cast<NetEConst*>(expr_); NetEConst*rval = dynamic_cast<NetEConst*>(expr_);
if (rval == 0) return 0; if (rval == 0) return 0;
verinum val = rval->value(); verinum val = rval->value();
verinum::V res; verinum::V res;
bool invert = false; bool invert = false;
@ -1717,16 +1740,16 @@ NetEConst* NetEUReduce::eval_tree(int prune_to_width)
the result of ! is V0. If there are no V1 bits the result of ! is V0. If there are no V1 bits
but there are some Vx/Vz bits, the result is but there are some Vx/Vz bits, the result is
unknown. Otherwise, the result is V1. */ unknown. Otherwise, the result is V1. */
unsigned v1 = 0, vx = 0; bool v1 = false, vx = false;
for (unsigned idx = 0 ; idx < val.len() ; idx += 1) { for (unsigned idx = 0 ; idx < val.len() && !v1 ; idx += 1) {
switch (val.get(idx)) { switch (val.get(idx)) {
case verinum::V0: case verinum::V0:
break; break;
case verinum::V1: case verinum::V1:
v1 += 1; v1 = true;
break; break;
default: default:
vx += 1; vx = true;
break; break;
} }
} }
@ -1781,15 +1804,27 @@ NetEConst* NetEUReduce::eval_tree(int prune_to_width)
} }
if (invert) res = ~res; if (invert) res = ~res;
return new NetEConst(verinum(res, 1));
NetEConst*tmp = new NetEConst(verinum(res, 1));
ivl_assert(*this, tmp);
tmp->set_line(*this);
if (debug_eval_tree)
cerr << get_fileline() << ": debug: Evaluated: " << *this
<< " --> " << *tmp << endl;
return tmp;
} }
NetExpr* evaluate_clog2(NetExpr*&arg_) NetExpr* evaluate_clog2(NetExpr*&arg_)
{ {
eval_expr(arg_); eval_expr(arg_);
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg_); NetEConst*tmpi = dynamic_cast<NetEConst *>(arg_);
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg_); NetECReal*tmpr = dynamic_cast<NetECReal *>(arg_);
if (tmpi || tmpr) {
if (tmpi == 0 && tmpr == 0) return 0;
verinum arg; verinum arg;
if (tmpi) { if (tmpi) {
arg = tmpi->value(); arg = tmpi->value();
@ -1797,16 +1832,19 @@ NetExpr* evaluate_clog2(NetExpr*&arg_)
arg = verinum(tmpr->value().as_double(), true); arg = verinum(tmpr->value().as_double(), true);
} }
NetEConst*rtn;
/* If we have an x in the verinum we return 'bx. */ /* If we have an x in the verinum we return 'bx. */
if (!arg.is_defined()) { if (!arg.is_defined()) {
verinum tmp (verinum::Vx, integer_width); verinum tmp (verinum::Vx, integer_width);
tmp.has_sign(true); tmp.has_sign(true);
NetEConst*rtn = new NetEConst(tmp);
return rtn;
}
rtn = new NetEConst(tmp);
ivl_assert(*arg_, rtn);
} else {
bool is_neg = false; bool is_neg = false;
uint64_t res = 0; uint64_t res = 0;
if (arg.is_negative()) { if (arg.is_negative()) {
is_neg = true; is_neg = true;
// If the length is not defined, then work with // If the length is not defined, then work with
@ -1829,11 +1867,12 @@ NetExpr* evaluate_clog2(NetExpr*&arg_)
verinum tmp (res, integer_width); verinum tmp (res, integer_width);
tmp.has_sign(true); tmp.has_sign(true);
NetEConst*rtn = new NetEConst(tmp);
return rtn; rtn = new NetEConst(tmp);
ivl_assert(*arg_, rtn);
} }
return 0; return rtn;
} }
NetExpr* evaluate_math_one_arg(NetExpr*&arg_, const char*name) NetExpr* evaluate_math_one_arg(NetExpr*&arg_, const char*name)
@ -1987,11 +2026,8 @@ NetExpr* evaluate_min_max(NetExpr*&arg0_, NetExpr*&arg1_, const char*name)
NetExpr* NetESFunc::eval_tree(int prune_to_width) NetExpr* NetESFunc::eval_tree(int prune_to_width)
{ {
if (debug_eval_tree) { // assert(prune_to_width <= 0);
cerr << get_fileline() << ": debug: Evaluating expression:" // HERE
<< *this << ", prune_to_width=" << prune_to_width << endl;
}
/* If we are not targeting at least Verilog-2005, Verilog-AMS /* If we are not targeting at least Verilog-2005, Verilog-AMS
* or using the Icarus misc flag then we do not support these * or using the Icarus misc flag then we do not support these
* functions as constant. */ * functions as constant. */
@ -2080,10 +2116,10 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width)
if (rtn != 0) { if (rtn != 0) {
rtn->set_line(*this); rtn->set_line(*this);
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluate constant " if (debug_eval_tree)
<< nm << "." << endl; cerr << get_fileline() << ": debug: Evaluated: " << *this
} << " --> " << *rtn << endl;
} }
return rtn; return rtn;

View File

@ -3832,6 +3832,9 @@ class NetEUReduce : public NetEUnary {
virtual NetEUReduce* dup_expr() const; virtual NetEUReduce* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree(int prune_to_width = -1);
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
private:
virtual NetEConst* eval_tree_real_();
}; };
class NetECast : public NetEUnary { class NetECast : public NetEUnary {