diff --git a/PExpr.h b/PExpr.h index cbc17b0fb..828acb83b 100644 --- a/PExpr.h +++ b/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); diff --git a/elab_expr.cc b/elab_expr.cc index 66f32d50e..b9a95cf4a 100644 --- a/elab_expr.cc +++ b/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 diff --git a/set_width.cc b/set_width.cc index 4aecfc849..cb736cea0 100644 --- a/set_width.cc +++ b/set_width.cc @@ -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)