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.
This commit is contained in:
Stephen Williams 2008-03-25 21:35:08 -07:00
parent 32b115d8fe
commit ea74eb771e
3 changed files with 36 additions and 8 deletions

View File

@ -808,13 +808,18 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width)
verinum lval = lc->value(); verinum lval = lc->value();
verinum rval = rc->value(); verinum rval = rc->value();
NetExpr*tmp = 0;
switch (op_) { switch (op_) {
case '/': case '/':
return new NetEConst(lval / rval); tmp = new NetEConst(lval / rval);
break;
case '%': case '%':
return new NetEConst(lval % rval); tmp = new NetEConst(lval % rval);
break;
} }
ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;
} }
return 0; return 0;
@ -919,7 +924,13 @@ NetExpr* NetEBMult::eval_tree(int prune_to_width)
verinum lval = lc->value(); verinum lval = lc->value();
verinum rval = rc->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_() NetExpr* NetEBPow::eval_tree_real_()

View File

@ -881,14 +881,18 @@ verinum operator * (const verinum&left, const verinum&right)
verinum result(verinum::V0, left.len() + right.len(), has_len_flag); verinum result(verinum::V0, left.len() + right.len(), has_len_flag);
result.has_sign(left.has_sign() || right.has_sign()); 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; continue;
verinum::V l_sign = sign_bit(left);
verinum::V carry = verinum::V0; verinum::V carry = verinum::V0;
for (unsigned ldx = 0 ; ldx < left.len() ; ldx += 1) { for (unsigned ldx = 0 ; ldx < result.len()-rdx ; ldx += 1) {
result.set(ldx+rdx, add_with_carry(left[ldx], verinum::V l_bit = ldx < left.len()? left[ldx] : l_sign;
result.set(ldx+rdx, add_with_carry(l_bit,
result[rdx+ldx], result[rdx+ldx],
carry)); carry));
} }

View File

@ -104,6 +104,19 @@ class verinum {
bool string_flag_; 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 /* 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 least as wide as the requested width. This may involve sign
extension, if the value is signed. */ extension, if the value is signed. */