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: protected:
NetAssign_* elaborate_lval(Design*, NetScope*scope) const; 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_; PExpr* delay_;
PEventStatement*event_; PEventStatement*event_;

View File

@ -31,6 +31,17 @@
# include "util.h" # include "util.h"
# include "ivl_assert.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 * The default behavior for the test_width method is to just return the
* minimum width that is passed in. * minimum width that is passed in.
@ -61,8 +72,8 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope,
{ {
bool flag_left = false; bool flag_left = false;
bool flag_right = false; bool flag_right = false;
unsigned wid_left = left_->test_width(des,scope, min, lval, flag_left); unsigned wid_left = left_->test_width(des,scope, min, 0, flag_left);
unsigned wid_right = right_->test_width(des,scope, min, lval, flag_right); unsigned wid_right = right_->test_width(des,scope, min, 0, flag_right);
if (flag_left || flag_right) if (flag_left || flag_right)
unsized_flag = true; unsized_flag = true;
@ -82,8 +93,16 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope,
min = lval; min = lval;
break; break;
case 'l': case 'l': // << Should be handled by PEBShift
ivl_assert(*this, 0); // Should be handled bin 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: default:
if (wid_left > min) if (wid_left > min)
min = wid_left; min = wid_left;
@ -114,6 +133,24 @@ NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope,
return 0; 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); NetExpr*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid);
return tmp; return tmp;
} }
@ -513,7 +550,17 @@ NetExpr* PEBinary::elaborate_expr_base_add_(Design*des,
int expr_wid) const int expr_wid) const
{ {
NetExpr*tmp; 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 if (expr_wid > 0 && (tmp->expr_type() == IVL_VT_BOOL
|| tmp->expr_type() == IVL_VT_LOGIC)) || tmp->expr_type() == IVL_VT_LOGIC))
tmp->set_width(expr_wid); tmp->set_width(expr_wid);

View File

@ -100,8 +100,14 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
} }
bool unsized_flag = false; bool unsized_flag = false;
unsigned use_width = pin(1)->test_width(des, scope, lval->vector_width(), 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); lval->vector_width(), unsized_flag);
}
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGAssign: r-value tested " 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(); int expr_wid = lval->vector_width();
if (use_width > (unsigned)expr_wid) if (use_width > (unsigned)expr_wid)
expr_wid = (int)use_width; 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), NetExpr*rval_expr = elab_and_eval(des, scope, pin(1),
expr_wid, lval->vector_width()); 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, 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_); ivl_assert(*this, rval_);
@ -1717,13 +1726,26 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
something else based on self-determined widths inside. */ something else based on self-determined widths inside. */
unsigned use_width = lv_width; unsigned use_width = lv_width;
bool unsized_flag = false; bool unsized_flag = false;
unsigned tmp_width = rval()->test_width(des, scope, use_width, use_width, unsized_flag); 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) if (tmp_width > use_width)
use_width = tmp_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 /* Now elaborate to the expected width. Pass the lwidth to
prune any constant result to fit with the lvalue at hand. */ 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; if (rv == 0) return 0;
return rv; return rv;
@ -1811,7 +1833,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
/* Elaborate the r-value expression, then try to evaluate it. */ /* 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; if (rv == 0) return 0;
assert(rv); assert(rv);
@ -1976,7 +1998,7 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
NetAssign_*lv = elaborate_lval(des, scope); NetAssign_*lv = elaborate_lval(des, scope);
if (lv == 0) return 0; 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 /* Handle the (common) case that the r-value is a vector. This
includes just about everything but reals. In this case, we includes just about everything but reals. In this case, we

View File

@ -81,6 +81,11 @@ unsigned NetAssign_::lwidth() const
return lwid_; return lwid_;
} }
ivl_variable_type_t NetAssign_::expr_type() const
{
return sig_->data_type();
}
perm_string NetAssign_::name() const perm_string NetAssign_::name() const
{ {
if (sig_) { if (sig_) {

View File

@ -2139,6 +2139,7 @@ class NetAssign_ {
// method accounts for the presence of the mux, so it is not // method accounts for the presence of the mux, so it is not
// necessarily the same as the pin_count(). // necessarily the same as the pin_count().
unsigned lwidth() const; unsigned lwidth() const;
ivl_variable_type_t expr_type() const;
// Get the name of the underlying object. // Get the name of the underlying object.
perm_string name() const; perm_string name() const;

View File

@ -81,6 +81,13 @@ static void show_binary_expression(ivl_expr_t net, unsigned ind)
switch (ivl_expr_opcode(net)) { switch (ivl_expr_opcode(net)) {
case '*': case '*':
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 /* The width of multiply expressions is the sum of the
widths of the operands. This is slightly different widths of the operands. This is slightly different
from the way the Verilog standard does it, but allows from the way the Verilog standard does it, but allows
@ -92,6 +99,7 @@ static void show_binary_expression(ivl_expr_t net, unsigned ind)
ind+3, "", width, ivl_expr_width(net)); ind+3, "", width, ivl_expr_width(net));
stub_errors += 1; stub_errors += 1;
} }
}
break; break;
default: default: