From 94a1d59817ecf12fae0b9e9130051015886c1cc5 Mon Sep 17 00:00:00 2001 From: steve Date: Wed, 7 Feb 2001 02:46:31 +0000 Subject: [PATCH] Support constant evaluation of / and % (PR#124) --- eval_tree.cc | 26 ++++++++++- verinum.cc | 125 ++++++++++++++++++++++++++++++++++++++++++++++++--- verinum.h | 8 +++- 3 files changed, 151 insertions(+), 8 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index 9eea93edf..62a2ffbe6 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: eval_tree.cc,v 1.21 2001/01/14 23:04:56 steve Exp $" +#ident "$Id: eval_tree.cc,v 1.22 2001/02/07 02:46:31 steve Exp $" #endif # include "netlist.h" @@ -363,9 +363,30 @@ NetEConst* NetEBComp::eval_tree() } } +/* + * The NetEBDiv operator includes the / and % opeators. First evaluate + * the sub-expressions, then perform the required operation. + */ NetEConst* NetEBDiv::eval_tree() { eval_sub_tree_(); + + NetEConst*lc = dynamic_cast(left_); + if (lc == 0) return 0; + NetEConst*rc = dynamic_cast(right_); + if (rc == 0) return 0; + + verinum lval = lc->value(); + verinum rval = rc->value(); + + switch (op_) { + case '/': + return new NetEConst(lval / rval); + + case '%': + return new NetEConst(lval % rval); + } + return 0; } @@ -822,6 +843,9 @@ NetEConst* NetEUReduce::eval_tree() /* * $Log: eval_tree.cc,v $ + * Revision 1.22 2001/02/07 02:46:31 steve + * Support constant evaluation of / and % (PR#124) + * * Revision 1.21 2001/01/14 23:04:56 steve * Generalize the evaluation of floating point delays, and * get it working with delay assignment statements. diff --git a/verinum.cc b/verinum.cc index 90494b65b..e498a04fe 100644 --- a/verinum.cc +++ b/verinum.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: verinum.cc,v 1.22 2001/01/02 03:23:40 steve Exp $" +#ident "$Id: verinum.cc,v 1.23 2001/02/07 02:46:31 steve Exp $" #endif # include "verinum.h" @@ -60,8 +60,8 @@ verinum::verinum(const string&str) } } -verinum::verinum(verinum::V val, unsigned n) -: has_len_(true), has_sign_(false), string_flag_(false) +verinum::verinum(verinum::V val, unsigned n, bool h) +: has_len_(h), has_sign_(false), string_flag_(false) { nbits_ = n; bits_ = new V[nbits_]; @@ -523,13 +523,18 @@ verinum operator - (const verinum&left, const verinum&r) */ verinum operator * (const verinum&left, const verinum&right) { + const bool has_len_flag = left.has_len() && right.has_len(); + + /* If either operand is not fully defined, then the entire + result is undefined. Create a result that is the right size + and is filled with 'bx bits. */ if (! (left.is_defined() && right.is_defined())) { - verinum result (verinum::Vx, left.len() + right.len()); + verinum result (verinum::Vx, left.len()+right.len(), has_len_flag); result.has_sign(left.has_sign() || right.has_sign()); return result; } - verinum result(verinum::V0, left.len() + right.len()); + verinum result(verinum::V0, left.len() + right.len(), has_len_flag); for (unsigned rdx = 0 ; rdx < right.len() ; rdx += 1) { @@ -548,6 +553,113 @@ verinum operator * (const verinum&left, const verinum&right) return result; } +/* + * This operator divides the left number by the right number. If + * either value is signed, the result is signed. If both values have a + * defined length, then the result has a defined length. + */ +verinum operator / (const verinum&left, const verinum&right) +{ + const bool has_len_flag = left.has_len() && right.has_len(); + + unsigned use_len = left.len(); + + /* If either operand is not fully defined, then the entire + result is undefined. Create a result that is the right size + and is filled with 'bx bits. */ + if (! (left.is_defined() && right.is_defined())) { + verinum result (verinum::Vx, use_len, has_len_flag); + result.has_sign(left.has_sign() || right.has_sign()); + return result; + } + + verinum result(verinum::Vz, use_len, has_len_flag); + result.has_sign(left.has_sign() || right.has_sign()); + + /* do the operation differently, depending on whether the + result is signed or not. */ + if (result.has_sign()) { + + /* XXXX FIXME XXXX Use native unsigned division to do + the work. This does not work if the result is too + large for the native integer. */ + assert(use_len <= 8*sizeof(long)); + long l = left.as_long(); + long r = right.as_long(); + long v = l / r; + for (unsigned idx = 0 ; idx < use_len ; idx += 1) { + result.set(idx, (v & 1)? verinum::V1 : verinum::V0); + v >>= 1; + } + + } else { + + /* XXXX FIXME XXXX Use native unsigned division to do + the work. This does not work if the result is too + large for the native integer. */ + assert(use_len <= 8*sizeof(unsigned long)); + unsigned long l = left.as_ulong(); + unsigned long r = right.as_ulong(); + unsigned long v = l / r; + for (unsigned idx = 0 ; idx < use_len ; idx += 1) { + result.set(idx, (v & 1)? verinum::V1 : verinum::V0); + v >>= 1; + } + } + + return result; +} + +verinum operator % (const verinum&left, const verinum&right) +{ + const bool has_len_flag = left.has_len() && right.has_len(); + + unsigned use_len = left.len(); + + /* If either operand is not fully defined, then the entire + result is undefined. Create a result that is the right size + and is filled with 'bx bits. */ + if (! (left.is_defined() && right.is_defined())) { + verinum result (verinum::Vx, use_len, has_len_flag); + result.has_sign(left.has_sign() || right.has_sign()); + return result; + } + + verinum result(verinum::Vz, use_len, has_len_flag); + result.has_sign(left.has_sign() || right.has_sign()); + + if (result.has_sign()) { + + /* XXXX FIXME XXXX Use native unsigned division to do + the work. This does not work if the result is too + large for the native integer. */ + assert(use_len <= 8*sizeof(long)); + long l = left.as_long(); + long r = right.as_long(); + long v = l % r; + for (unsigned idx = 0 ; idx < use_len ; idx += 1) { + result.set(idx, (v & 1)? verinum::V1 : verinum::V0); + v >>= 1; + } + + } else { + + /* XXXX FIXME XXXX Use native unsigned division to do + the work. This does not work if the result is too + large for the native integer. */ + assert(use_len <= 8*sizeof(unsigned long)); + unsigned long l = left.as_ulong(); + unsigned long r = right.as_ulong(); + unsigned long v = l % r; + for (unsigned idx = 0 ; idx < use_len ; idx += 1) { + result.set(idx, (v & 1)? verinum::V1 : verinum::V0); + v >>= 1; + } + } + + return result; +} + verinum::V operator | (verinum::V l, verinum::V r) { if (l == verinum::V1) @@ -576,6 +688,9 @@ verinum::V operator & (verinum::V l, verinum::V r) /* * $Log: verinum.cc,v $ + * Revision 1.23 2001/02/07 02:46:31 steve + * Support constant evaluation of / and % (PR#124) + * * Revision 1.22 2001/01/02 03:23:40 steve * Evaluate constant &, | and unary ~. * diff --git a/verinum.h b/verinum.h index c89ea15f5..9e792e9d6 100644 --- a/verinum.h +++ b/verinum.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: verinum.h,v 1.15 2001/01/16 02:44:18 steve Exp $" +#ident "$Id: verinum.h,v 1.16 2001/02/07 02:46:31 steve Exp $" #endif # include @@ -44,7 +44,7 @@ class verinum { verinum(); verinum(const string&str); verinum(const V*v, unsigned nbits, bool has_len =true); - verinum(V, unsigned nbits =1); + verinum(V, unsigned nbits =1, bool has_len =true); verinum(unsigned long val, unsigned bits); verinum(const verinum&); @@ -114,11 +114,15 @@ extern verinum operator + (const verinum&left, const verinum&right); extern verinum operator - (const verinum&left, const verinum&right); extern verinum operator * (const verinum&left, const verinum&right); extern verinum operator / (const verinum&left, const verinum&right); +extern verinum operator % (const verinum&left, const verinum&right); extern verinum v_not(const verinum&left); /* * $Log: verinum.h,v $ + * Revision 1.16 2001/02/07 02:46:31 steve + * Support constant evaluation of / and % (PR#124) + * * Revision 1.15 2001/01/16 02:44:18 steve * Use the iosfwd header if available. *