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:
Stephen Williams 2008-09-22 21:09:06 -07:00
parent 2381fc72b0
commit ce7dd6b4ff
6 changed files with 109 additions and 25 deletions

View File

@ -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_;

View File

@ -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);

View File

@ -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

View File

@ -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_) {

View File

@ -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;

View File

@ -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;