Pad signed arguments to multiply

Arguments to multiply that are signed must be the width of the output
for the 2s complement multiply to work correctly.
This commit is contained in:
Stephen Williams 2008-09-19 22:00:29 -07:00
parent 103b351641
commit 46bf03bba4
3 changed files with 39 additions and 10 deletions

View File

@ -455,6 +455,7 @@ class PEBinary : public PExpr {
NetExpr*elaborate_expr_base_lshift_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_rshift_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_mult_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_add_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
static void suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp);

View File

@ -181,15 +181,7 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
break;
case '*':
// Multiply will guess a width that is the sum of the
// widths of the operand. If that sum is too small, then
// pad one of the arguments enough that the sum is the
// desired width.
if (expr_wid > (long)(lp->expr_width() + rp->expr_width()))
lp = pad_to_width(lp, expr_wid - rp->expr_width());
tmp = new NetEBMult(op_, lp, rp);
tmp->set_line(*this);
tmp = elaborate_expr_base_mult_(des, lp, rp, expr_wid);
break;
case '%':
@ -484,6 +476,36 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
return tmp;
}
NetExpr* PEBinary::elaborate_expr_base_mult_(Design*des,
NetExpr*lp, NetExpr*rp,
int expr_wid) const
{
// First, Make sure that signed arguments are padded to the
// width of the output. This is necessary for 2s complement
// multiplication to come out right.
if (expr_wid > 0) {
if (lp->has_sign() && lp->expr_type() != IVL_VT_REAL)
lp = pad_to_width(lp, expr_wid);
if (rp->has_sign() && rp->expr_type() != IVL_VT_REAL)
rp = pad_to_width(rp, expr_wid);
}
// Multiply will guess a width that is the sum of the
// widths of the operand. If that sum is too small, then
// pad one of the arguments enough that the sum is the
// desired width.
if (expr_wid > (long)(lp->expr_width() + rp->expr_width()))
lp = pad_to_width(lp, expr_wid - rp->expr_width());
NetEBMult*tmp = new NetEBMult(op_, lp, rp);
tmp->set_line(*this);
if (expr_wid > 0)
tmp->set_width(expr_wid, false);
return tmp;
}
NetExpr* PEBinary::elaborate_expr_base_add_(Design*des,
NetExpr*lp, NetExpr*rp,
int expr_wid) const

View File

@ -180,7 +180,13 @@ bool NetEBLogic::set_width(unsigned w, bool)
*/
bool NetEBMult::set_width(unsigned w, bool)
{
return w == expr_width();
if (w < left_->expr_width())
left_->set_width(w);
if (w < right_->expr_width())
right_->expr_width();
expr_width(w);
return true;
}
bool NetEBPow::set_width(unsigned w, bool last_chance)