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 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_()

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);
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));
}

View File

@ -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. */