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:
parent
103b351641
commit
46bf03bba4
1
PExpr.h
1
PExpr.h
|
|
@ -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);
|
||||
|
|
|
|||
40
elab_expr.cc
40
elab_expr.cc
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue