From f993e78185ac3a424b721ab80b48b8a2678dac8d Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 8 Jan 2009 17:43:40 -0800 Subject: [PATCH] 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. --- eval_tree.cc | 119 +++++++++++++++++++++------------------------------ netlist.h | 10 ++--- 2 files changed, 52 insertions(+), 77 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index 9a9843c13..d6fee2429 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -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 * 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 sub-expressions, then perform the required operation. @@ -827,77 +852,31 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width) eval_expr(left_); eval_expr(right_); - if (expr_type() == IVL_VT_REAL) { - NetECReal*lc = dynamic_cast(left_); - if (lc == 0) return 0; + if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); + + assert(expr_type() == IVL_VT_LOGIC); - verireal lval = lc->value(); + NetEConst*lc = dynamic_cast(left_); + NetEConst*rc = dynamic_cast(right_); + if (lc == 0 || rc == 0) return 0; - if (NetECReal*rcr = dynamic_cast(right_)) { - NetECReal*tmp = 0; - verireal rval = rcr->value(); + // 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()); - switch (op_) { - case '/': - tmp = new NetECReal(lval / rval); - break; - - case '%': - tmp = new NetECReal(lval % rval); - } - - assert(tmp); - tmp->set_line(*this); - return tmp; - - } else if (NetEConst*rc = dynamic_cast(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(left_); - if (lc == 0) return 0; - NetEConst*rc = dynamic_cast(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; + NetExpr*tmp = 0; + switch (op_) { + case '/': + tmp = new NetEConst(lval / rval); + break; + case '%': + tmp = new NetEConst(lval % rval); + break; } - - return 0; + ivl_assert(*this, tmp); + tmp->set_line(*this); + return tmp; } NetEConst* NetEBLogic::eval_tree(int prune_to_width) @@ -976,7 +955,6 @@ NetExpr* NetEBMult::eval_tree_real_() bool flag = get_real_arguments_(lval, rval); if (! flag) return 0; - NetECReal*res = new NetECReal(lval * rval); res->set_line(*this); return res; @@ -987,8 +965,7 @@ NetExpr* NetEBMult::eval_tree(int prune_to_width) eval_expr(left_); eval_expr(right_); - if (expr_type() == IVL_VT_REAL) - return eval_tree_real_(); + if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); assert(expr_type() == IVL_VT_LOGIC); diff --git a/netlist.h b/netlist.h index 37ef42b0a..78bebb4a6 100644 --- a/netlist.h +++ b/netlist.h @@ -1,7 +1,7 @@ #ifndef __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 * 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 NetExpr* eval_tree(int prune_to_width = -1); 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; private: - }; /* @@ -3406,9 +3408,7 @@ class NetEBMult : public NetEBinary { virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: - NetExpr* eval_tree_real_(); - }; /* @@ -3428,9 +3428,7 @@ class NetEBPow : public NetEBinary { virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: - NetExpr* eval_tree_real_(); - };