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:
parent
32b115d8fe
commit
ea74eb771e
19
eval_tree.cc
19
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_()
|
||||
|
|
|
|||
12
verinum.cc
12
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));
|
||||
}
|
||||
|
|
|
|||
13
verinum.h
13
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. */
|
||||
|
|
|
|||
Loading…
Reference in New Issue