Account for real type l-values when working with widths.
Widths of real values are always 1. When paired with vectorable types
in expressions, the vectorable type is processed as losslessly self-
determined. ("unsized" in the test_width methods.)
This commit is contained in:
parent
2381fc72b0
commit
ce7dd6b4ff
|
|
@ -103,7 +103,8 @@ class PAssign_ : public Statement {
|
|||
|
||||
protected:
|
||||
NetAssign_* elaborate_lval(Design*, NetScope*scope) const;
|
||||
NetExpr* elaborate_rval_(Design*, NetScope*, unsigned lv_width) const;
|
||||
NetExpr* elaborate_rval_(Design*, NetScope*, unsigned lv_width,
|
||||
ivl_variable_type_t type) const;
|
||||
|
||||
PExpr* delay_;
|
||||
PEventStatement*event_;
|
||||
|
|
|
|||
57
elab_expr.cc
57
elab_expr.cc
|
|
@ -31,6 +31,17 @@
|
|||
# include "util.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
static bool type_is_vectorable(ivl_variable_type_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case IVL_VT_BOOL:
|
||||
case IVL_VT_LOGIC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The default behavior for the test_width method is to just return the
|
||||
* minimum width that is passed in.
|
||||
|
|
@ -61,8 +72,8 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope,
|
|||
{
|
||||
bool flag_left = false;
|
||||
bool flag_right = false;
|
||||
unsigned wid_left = left_->test_width(des,scope, min, lval, flag_left);
|
||||
unsigned wid_right = right_->test_width(des,scope, min, lval, flag_right);
|
||||
unsigned wid_left = left_->test_width(des,scope, min, 0, flag_left);
|
||||
unsigned wid_right = right_->test_width(des,scope, min, 0, flag_right);
|
||||
|
||||
if (flag_left || flag_right)
|
||||
unsized_flag = true;
|
||||
|
|
@ -82,8 +93,16 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope,
|
|||
min = lval;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
ivl_assert(*this, 0); // Should be handled bin PEBShift
|
||||
case 'l': // << Should be handled by PEBShift
|
||||
case '<': // < Should be handled by PEBComp
|
||||
case '>': // > Should be handled by PEBComp
|
||||
case 'e': // == Should be handled by PEBComp
|
||||
case 'E': // === Should be handled by PEBComp
|
||||
case 'L': // <= Should be handled by PEBComp
|
||||
case 'G': // >= Should be handled by PEBComp
|
||||
case 'n': // != Should be handled by PEBComp
|
||||
case 'N': // !== Should be handled by PEBComp
|
||||
ivl_assert(*this, 0);
|
||||
default:
|
||||
if (wid_left > min)
|
||||
min = wid_left;
|
||||
|
|
@ -114,6 +133,24 @@ NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Handle the special case that one of the operands is a real
|
||||
// value and the other is a vector type. In that case,
|
||||
// re-elaborate the vectorable argument as self-determined
|
||||
// lossless.
|
||||
if (lp->expr_type()==IVL_VT_REAL
|
||||
&& type_is_vectorable(rp->expr_type())
|
||||
&& expr_wid != -2) {
|
||||
delete rp;
|
||||
rp = right_->elaborate_expr(des, scope, -2, false);
|
||||
}
|
||||
|
||||
if (rp->expr_type()==IVL_VT_REAL
|
||||
&& type_is_vectorable(lp->expr_type())
|
||||
&& expr_wid != -2) {
|
||||
delete lp;
|
||||
lp = left_->elaborate_expr(des, scope, -2, false);
|
||||
}
|
||||
|
||||
NetExpr*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -513,7 +550,17 @@ NetExpr* PEBinary::elaborate_expr_base_add_(Design*des,
|
|||
int expr_wid) const
|
||||
{
|
||||
NetExpr*tmp;
|
||||
tmp = new NetEBAdd(op_, lp, rp, expr_wid==-2? true : false);
|
||||
bool use_lossless_flag = expr_wid == -2;
|
||||
|
||||
// If this expression is not vectorable, then do NOT pass the
|
||||
// lossless flag to the NetEBAdd constructor. For non-
|
||||
// vectorable, lossless is implicit.
|
||||
if (! type_is_vectorable(lp->expr_type()))
|
||||
use_lossless_flag = false;
|
||||
if (! type_is_vectorable(rp->expr_type()))
|
||||
use_lossless_flag = false;
|
||||
|
||||
tmp = new NetEBAdd(op_, lp, rp, use_lossless_flag);
|
||||
if (expr_wid > 0 && (tmp->expr_type() == IVL_VT_BOOL
|
||||
|| tmp->expr_type() == IVL_VT_LOGIC))
|
||||
tmp->set_width(expr_wid);
|
||||
|
|
|
|||
40
elaborate.cc
40
elaborate.cc
|
|
@ -100,8 +100,14 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
|||
}
|
||||
|
||||
bool unsized_flag = false;
|
||||
unsigned use_width = pin(1)->test_width(des, scope, lval->vector_width(),
|
||||
lval->vector_width(), unsized_flag);
|
||||
unsigned use_width = 0;
|
||||
if (lval->data_type() == IVL_VT_REAL) {
|
||||
unsized_flag = true;
|
||||
use_width = pin(1)->test_width(des, scope, 0, 0, unsized_flag);
|
||||
} else {
|
||||
use_width = pin(1)->test_width(des, scope, lval->vector_width(),
|
||||
lval->vector_width(), unsized_flag);
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: PGAssign: r-value tested "
|
||||
|
|
@ -113,6 +119,8 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
|||
int expr_wid = lval->vector_width();
|
||||
if (use_width > (unsigned)expr_wid)
|
||||
expr_wid = (int)use_width;
|
||||
if (lval->data_type() == IVL_VT_REAL)
|
||||
expr_wid = -2;
|
||||
|
||||
NetExpr*rval_expr = elab_and_eval(des, scope, pin(1),
|
||||
expr_wid, lval->vector_width());
|
||||
|
|
@ -1707,7 +1715,8 @@ NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const
|
|||
}
|
||||
|
||||
NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
|
||||
unsigned lv_width) const
|
||||
unsigned lv_width,
|
||||
ivl_variable_type_t lv_type) const
|
||||
{
|
||||
ivl_assert(*this, rval_);
|
||||
|
||||
|
|
@ -1717,13 +1726,26 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
|
|||
something else based on self-determined widths inside. */
|
||||
unsigned use_width = lv_width;
|
||||
bool unsized_flag = false;
|
||||
unsigned tmp_width = rval()->test_width(des, scope, use_width, use_width, unsized_flag);
|
||||
if (tmp_width > use_width)
|
||||
use_width = tmp_width;
|
||||
unsigned tmp_width = 0;
|
||||
|
||||
if (lv_type == IVL_VT_REAL) {
|
||||
unsized_flag = true;
|
||||
tmp_width = rval()->test_width(des, scope, 0, 0, unsized_flag);
|
||||
} else {
|
||||
tmp_width = rval()->test_width(des, scope, use_width, use_width, unsized_flag);
|
||||
if (tmp_width > use_width)
|
||||
use_width = tmp_width;
|
||||
}
|
||||
|
||||
int expr_wid = use_width;
|
||||
if (lv_type == IVL_VT_REAL) {
|
||||
expr_wid = -2;
|
||||
lv_width = 0;
|
||||
}
|
||||
|
||||
/* Now elaborate to the expected width. Pass the lwidth to
|
||||
prune any constant result to fit with the lvalue at hand. */
|
||||
NetExpr*rv = elab_and_eval(des, scope, rval_, use_width, lv_width);
|
||||
NetExpr*rv = elab_and_eval(des, scope, rval_, expr_wid, lv_width);
|
||||
if (rv == 0) return 0;
|
||||
|
||||
return rv;
|
||||
|
|
@ -1811,7 +1833,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
|
||||
|
||||
/* Elaborate the r-value expression, then try to evaluate it. */
|
||||
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv));
|
||||
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
|
||||
if (rv == 0) return 0;
|
||||
assert(rv);
|
||||
|
||||
|
|
@ -1976,7 +1998,7 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
|
|||
NetAssign_*lv = elaborate_lval(des, scope);
|
||||
if (lv == 0) return 0;
|
||||
|
||||
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv));
|
||||
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
|
||||
|
||||
/* Handle the (common) case that the r-value is a vector. This
|
||||
includes just about everything but reals. In this case, we
|
||||
|
|
|
|||
|
|
@ -81,6 +81,11 @@ unsigned NetAssign_::lwidth() const
|
|||
return lwid_;
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetAssign_::expr_type() const
|
||||
{
|
||||
return sig_->data_type();
|
||||
}
|
||||
|
||||
perm_string NetAssign_::name() const
|
||||
{
|
||||
if (sig_) {
|
||||
|
|
|
|||
|
|
@ -2139,6 +2139,7 @@ class NetAssign_ {
|
|||
// method accounts for the presence of the mux, so it is not
|
||||
// necessarily the same as the pin_count().
|
||||
unsigned lwidth() const;
|
||||
ivl_variable_type_t expr_type() const;
|
||||
|
||||
// Get the name of the underlying object.
|
||||
perm_string name() const;
|
||||
|
|
|
|||
|
|
@ -81,16 +81,24 @@ static void show_binary_expression(ivl_expr_t net, unsigned ind)
|
|||
switch (ivl_expr_opcode(net)) {
|
||||
|
||||
case '*':
|
||||
/* 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));
|
||||
stub_errors += 1;
|
||||
if (ivl_expr_value(net) == IVL_VT_REAL) {
|
||||
if (ivl_expr_width(net) != 1) {
|
||||
fprintf(out, "%*sERROR: Result width incorrect. Expecting 1, got %u\n",
|
||||
ind+3, "", ivl_expr_width(net));
|
||||
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));
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue