diff --git a/net_expr.cc b/net_expr.cc index 90ea8cbf8..96f46d298 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -242,7 +242,11 @@ ivl_variable_type_t NetEBMinMax::expr_type() const NetEBMult::NetEBMult(char op, NetExpr*l, NetExpr*r) : NetEBinary(op, l, r) { - expr_width(l->expr_width() + r->expr_width()); + if (expr_type() == IVL_VT_REAL) + expr_width(1); + else + expr_width(l->expr_width() + r->expr_width()); + cast_signed(l->has_sign() && r->has_sign()); /* If it turns out that this is not a signed expression, then diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 5adc6b8b4..5a21a6a7a 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -88,15 +88,19 @@ static void show_binary_expression(ivl_expr_t net, unsigned ind) stub_errors += 1; } } else { - /* The width of multiply expressions is the sum of the - widths of the operands. This is slightly different - from the way the Verilog standard does it, but allows - us to keep operands smaller. */ - width = ivl_expr_width(ivl_expr_oper1(net)); - width += ivl_expr_width(ivl_expr_oper2(net)); - if (ivl_expr_width(net) != width) { - fprintf(out, "%*sERROR: Result width incorrect. Expecting %u, got %u\n", - ind+3, "", width, ivl_expr_width(net)); + /* The width of a multiply may be any width. The + implicit assumption is that the multiply + returns a width that is the sum of the widths + of the arguments, that is then truncated to the + desired width, never padded. The compiler will + automatically take care of sign extensions of + arguments, so that the code generator need only + generate an UNSIGNED multiply, and the result + will come out right. */ + unsigned max_width = ivl_expr_width(oper1) + ivl_expr_width(oper2); + if (ivl_expr_width(net) > max_width) { + fprintf(out, "%*sERROR: Result width to width. Expecting <= %u, got %u\n", + ind+3, "", max_width, ivl_expr_width(net)); stub_errors += 1; } }