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,31 +965,29 @@ 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;
else if ((lv == verinum::V1) && (rv == verinum::V1)) else if ((lv == verinum::V1) && (rv == verinum::V1))
res = verinum::V1; res = verinum::V1;
else else
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;
else if ((lv == verinum::V0) && (rv == verinum::V0)) else if ((lv == verinum::V0) && (rv == verinum::V0))
res = verinum::V0; res = verinum::V0;
else else
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,47 +1643,52 @@ 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());
tmp.has_sign(val.has_sign());
val = tmp - val;
} else {
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
val.set(idx, verinum::Vx);
}
break;
verinum tmp (verinum::V0, val.len()); case '~':
tmp.has_sign(val.has_sign()); /* Bitwise not is even simpler then logical
val = tmp - val; not. Just invert all the bits of the operand and
make the new value with the same dimensions. */
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
switch (val.get(idx)) {
case verinum::V0:
val.set(idx, verinum::V1);
break;
case verinum::V1:
val.set(idx, verinum::V0);
break;
default:
val.set(idx, verinum::Vx);
}
} else { break;
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
val.set(idx, verinum::Vx);
}
return new NetEConst(val);
}
case '~': {
/* Bitwise not is even simpler then logical
not. Just invert all the bits of the operand and
make the new value with the same dimensions. */
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
switch (val.get(idx)) {
case verinum::V0:
val.set(idx, verinum::V1);
break;
case verinum::V1:
val.set(idx, verinum::V0);
break;
default:
val.set(idx, verinum::Vx);
}
return new NetEConst(val);
}
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,32 +1804,47 @@ 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) {
verinum arg;
if (tmpi) {
arg = tmpi->value();
} else {
arg = verinum(tmpr->value().as_double(), true);
}
/* If we have an x in the verinum we return 'bx. */ if (tmpi == 0 && tmpr == 0) return 0;
if (!arg.is_defined()) {
verinum tmp (verinum::Vx, integer_width);
tmp.has_sign(true);
NetEConst*rtn = new NetEConst(tmp);
return rtn;
}
verinum arg;
if (tmpi) {
arg = tmpi->value();
} else {
arg = verinum(tmpr->value().as_double(), true);
}
NetEConst*rtn;
/* If we have an x in the verinum we return 'bx. */
if (!arg.is_defined()) {
verinum tmp (verinum::Vx, integer_width);
tmp.has_sign(true);
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 {