From ea74eb771ebeff4d8d9f8612b089cd07a8ed8941 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 25 Mar 2008 21:35:08 -0700 Subject: [PATCH] Fix a couple problems with signed multiply Problems with signed expressions that are set to parameters and that include multipliciation exposed a few bugs in the calculation of signed multiply. Fix this and add some improved diagnostics. --- eval_tree.cc | 19 +++++++++++++++---- verinum.cc | 12 ++++++++---- verinum.h | 13 +++++++++++++ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index 1dd138421..93d6d949e 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -808,13 +808,18 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width) verinum lval = lc->value(); verinum rval = rc->value(); + NetExpr*tmp = 0; switch (op_) { case '/': - return new NetEConst(lval / rval); - + tmp = new NetEConst(lval / rval); + break; case '%': - return new NetEConst(lval % rval); + tmp = new NetEConst(lval % rval); + break; } + ivl_assert(*this, tmp); + tmp->set_line(*this); + return tmp; } return 0; @@ -919,7 +924,13 @@ NetExpr* NetEBMult::eval_tree(int prune_to_width) verinum lval = lc->value(); verinum rval = rc->value(); - return new NetEConst(lval * rval); + NetEConst*tmp = new NetEConst(lval * rval); + + if (debug_eval_tree) + cerr << get_fileline() << ": debug: Evaluate " + << lval << " * " << rval << " --> " << *tmp << endl; + + return tmp; } NetExpr* NetEBPow::eval_tree_real_() diff --git a/verinum.cc b/verinum.cc index 05f2ef25c..d7ed2a25a 100644 --- a/verinum.cc +++ b/verinum.cc @@ -881,14 +881,18 @@ verinum operator * (const verinum&left, const verinum&right) verinum result(verinum::V0, left.len() + right.len(), has_len_flag); result.has_sign(left.has_sign() || right.has_sign()); - for (unsigned rdx = 0 ; rdx < right.len() ; rdx += 1) { + verinum::V r_sign = sign_bit(right); + for (unsigned rdx = 0 ; rdx < result.len() ; rdx += 1) { - if (right.get(rdx) == verinum::V0) + verinum::V r_bit = rdx < right.len()? right.get(rdx) : r_sign; + if (r_bit == verinum::V0) continue; + verinum::V l_sign = sign_bit(left); verinum::V carry = verinum::V0; - for (unsigned ldx = 0 ; ldx < left.len() ; ldx += 1) { - result.set(ldx+rdx, add_with_carry(left[ldx], + for (unsigned ldx = 0 ; ldx < result.len()-rdx ; ldx += 1) { + verinum::V l_bit = ldx < left.len()? left[ldx] : l_sign; + result.set(ldx+rdx, add_with_carry(l_bit, result[rdx+ldx], carry)); } diff --git a/verinum.h b/verinum.h index 4670e45c9..f400a1a5c 100644 --- a/verinum.h +++ b/verinum.h @@ -104,6 +104,19 @@ class verinum { bool string_flag_; }; +/* + * This returns the sign bit of the verinum value. If the value is + * unsigned, then return an implicit sign bit of 0. Otherwise, return + * the high bit. + */ +inline verinum::V sign_bit(const verinum&val) +{ + if (val.has_sign()) + return val.get(val.len()-1); + else + return verinum::V0; +} + /* Return a verinum that has the same value as the input, but is at least as wide as the requested width. This may involve sign extension, if the value is signed. */