Make eval_tree mixed case div/mod work.

This patch makes constant mixed case division or modulus
optimize correctly. The modulus is only done if the
gn_icarus_misc_flag is set.
This commit is contained in:
Cary R 2009-01-08 17:43:40 -08:00 committed by Stephen Williams
parent f2f7933708
commit f993e78185
2 changed files with 52 additions and 77 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2009 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
@ -818,6 +818,31 @@ NetEConst* NetEBComp::eval_tree(int prune_to_width)
} }
} }
NetExpr* NetEBDiv::eval_tree_real_()
{
verireal lval;
verireal rval;
bool flag = get_real_arguments_(lval, rval);
if (! flag) return 0;
NetECReal*res = 0;
switch (op_) {
case '/':
res = new NetECReal(lval / rval);
break;
case '%':
// Since this could be called early we don't want this to leak functionality.
if (!gn_icarus_misc_flag) return 0;
res = new NetECReal(verireal(fmod(lval.as_double(), rval.as_double())));
break;
}
ivl_assert(*this, res);
res->set_line(*this);
return res;
}
/* /*
* The NetEBDiv operator includes the / and % operators. First evaluate * The NetEBDiv operator includes the / and % operators. First evaluate
* the sub-expressions, then perform the required operation. * the sub-expressions, then perform the required operation.
@ -827,77 +852,31 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width)
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
if (expr_type() == IVL_VT_REAL) { if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
NetECReal*lc = dynamic_cast<NetECReal*>(left_);
if (lc == 0) return 0; assert(expr_type() == IVL_VT_LOGIC);
verireal lval = lc->value(); NetEConst*lc = dynamic_cast<NetEConst*>(left_);
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
if (lc == 0 || rc == 0) return 0;
if (NetECReal*rcr = dynamic_cast<NetECReal*>(right_)) { // Make sure the expression is evaluated at the
NetECReal*tmp = 0; // expression width.
verireal rval = rcr->value(); verinum lval = pad_to_width(lc->value(), expr_width());
verinum rval = pad_to_width(rc->value(), expr_width());
switch (op_) { NetExpr*tmp = 0;
case '/': switch (op_) {
tmp = new NetECReal(lval / rval); case '/':
break; tmp = new NetEConst(lval / rval);
break;
case '%': case '%':
tmp = new NetECReal(lval % rval); tmp = new NetEConst(lval % rval);
} break;
assert(tmp);
tmp->set_line(*this);
return tmp;
} else if (NetEConst*rc = dynamic_cast<NetEConst*>(right_)) {
NetECReal*tmp = 0;
verinum rval = rc->value();
switch (op_) {
case '/':
tmp = new NetECReal(lval / rval);
break;
case '%':
tmp = new NetECReal(lval % rval);
}
assert(tmp);
tmp->set_line(*this);
return tmp;
}
} else {
assert(expr_type() == IVL_VT_LOGIC);
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
if (lc == 0) return 0;
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
if (rc == 0) return 0;
// Make sure the expression is evaluated at the
// expression width.
verinum lval = pad_to_width(lc->value(), expr_width());
verinum rval = pad_to_width(rc->value(), expr_width());
NetExpr*tmp = 0;
switch (op_) {
case '/':
tmp = new NetEConst(lval / rval);
break;
case '%':
tmp = new NetEConst(lval % rval);
break;
}
ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;
} }
ivl_assert(*this, tmp);
return 0; tmp->set_line(*this);
return tmp;
} }
NetEConst* NetEBLogic::eval_tree(int prune_to_width) NetEConst* NetEBLogic::eval_tree(int prune_to_width)
@ -976,7 +955,6 @@ NetExpr* NetEBMult::eval_tree_real_()
bool flag = get_real_arguments_(lval, rval); bool flag = get_real_arguments_(lval, rval);
if (! flag) return 0; if (! flag) return 0;
NetECReal*res = new NetECReal(lval * rval); NetECReal*res = new NetECReal(lval * rval);
res->set_line(*this); res->set_line(*this);
return res; return res;
@ -987,8 +965,7 @@ NetExpr* NetEBMult::eval_tree(int prune_to_width)
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
if (expr_type() == IVL_VT_REAL) if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
return eval_tree_real_();
assert(expr_type() == IVL_VT_LOGIC); assert(expr_type() == IVL_VT_LOGIC);

View File

@ -1,7 +1,7 @@
#ifndef __netlist_H #ifndef __netlist_H
#define __netlist_H #define __netlist_H
/* /*
* Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2009 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
@ -3276,6 +3276,9 @@ class NetEBDiv : public NetEBinary {
virtual NetEBDiv* dup_expr() const; virtual NetEBDiv* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private:
NetExpr* eval_tree_real_();
}; };
/* /*
@ -3386,7 +3389,6 @@ class NetEBMinMax : public NetEBinary {
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
private: private:
}; };
/* /*
@ -3406,9 +3408,7 @@ class NetEBMult : 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_tree_real_();
}; };
/* /*
@ -3428,9 +3428,7 @@ 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_tree_real_();
}; };