Use the expression with to calculate expression width in assignments.
In continuous assignment, the width of the expression needs to come from the expression itself, and not just from the width of the l-value. Use the PExpr::test_width method to get the width of the expression to pass to the elaborate.
This commit is contained in:
parent
c26ee8534d
commit
b2b0f45473
146
elab_expr.cc
146
elab_expr.cc
|
|
@ -229,11 +229,7 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
|
|||
|
||||
case '+':
|
||||
case '-':
|
||||
tmp = new NetEBAdd(op_, lp, rp, expr_wid==-2? true : false);
|
||||
if (expr_wid > 0 && (tmp->expr_type() == IVL_VT_BOOL
|
||||
|| tmp->expr_type() == IVL_VT_LOGIC))
|
||||
tmp->set_width(expr_wid);
|
||||
tmp->set_line(*this);
|
||||
tmp = elaborate_expr_base_add_(des, lp, rp, expr_wid);
|
||||
break;
|
||||
|
||||
case 'E': /* === */
|
||||
|
|
@ -301,6 +297,12 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,
|
|||
return tmp;
|
||||
}
|
||||
|
||||
// If the left expression is constant, then there are some
|
||||
// special cases we can work with. If the left expression is
|
||||
// not constant, but the right expression is constant, then
|
||||
// there are some other interesting cases. But if neither are
|
||||
// constant, then there is the general case.
|
||||
|
||||
if (NetEConst*lpc = dynamic_cast<NetEConst*> (lp)) {
|
||||
if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
|
||||
// Handle the super-special case that both
|
||||
|
|
@ -313,16 +315,17 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,
|
|||
// there is a context determined size, use that.
|
||||
if (lpval.has_len() || expr_wid > 0) {
|
||||
int use_len = lpval.len();
|
||||
if (expr_wid < use_len)
|
||||
if (expr_wid > 0 && expr_wid > use_len)
|
||||
use_len = expr_wid;
|
||||
result = verinum(result, lpval.len());
|
||||
result = verinum(result, use_len);
|
||||
}
|
||||
|
||||
tmp = new NetEConst(result);
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Precalculate " << *this
|
||||
<< " to constant " << *tmp << endl;
|
||||
<< "Precalculate " << *lpc << " << " << shift
|
||||
<< " to constant " << *tmp
|
||||
<< " (expr_wid=" << expr_wid << ")" << endl;
|
||||
|
||||
} else {
|
||||
// Handle the special case that the left
|
||||
|
|
@ -479,6 +482,19 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
|
|||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr* PEBinary::elaborate_expr_base_add_(Design*des,
|
||||
NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const
|
||||
{
|
||||
NetExpr*tmp;
|
||||
tmp = new NetEBAdd(op_, lp, rp, expr_wid==-2? true : false);
|
||||
if (expr_wid > 0 && (tmp->expr_type() == IVL_VT_BOOL
|
||||
|| tmp->expr_type() == IVL_VT_LOGIC))
|
||||
tmp->set_width(expr_wid);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, bool&) const
|
||||
{
|
||||
return 1;
|
||||
|
|
@ -532,6 +548,11 @@ unsigned PEBShift::test_width(Design*des, NetScope*scope,
|
|||
// The right expression is self-determined and has no impact
|
||||
// on the expression size that is generated.
|
||||
|
||||
if (wid_left < min)
|
||||
wid_left = min;
|
||||
if (wid_left < lval)
|
||||
wid_left = lval;
|
||||
|
||||
return wid_left;
|
||||
}
|
||||
|
||||
|
|
@ -1096,36 +1117,70 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope,
|
|||
|
||||
symbol_search(des, scope, path_, net, par, eve, ex1, ex2);
|
||||
|
||||
if (net != 0) {
|
||||
const name_component_t&name_tail = path_.back();
|
||||
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
||||
if (!name_tail.index.empty())
|
||||
use_sel = name_tail.index.back().sel;
|
||||
// If there is a part/bit select expression, then process it
|
||||
// here. This constrains the results no matter what kind the
|
||||
// name is.
|
||||
|
||||
unsigned use_width = net->vector_width();
|
||||
switch (use_sel) {
|
||||
case index_component_t::SEL_NONE:
|
||||
break;
|
||||
case index_component_t::SEL_PART:
|
||||
{ long msb, lsb;
|
||||
calculate_parts_(des, scope, msb, lsb);
|
||||
use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb));
|
||||
break;
|
||||
}
|
||||
case index_component_t::SEL_IDX_UP:
|
||||
case index_component_t::SEL_IDX_DO:
|
||||
{ unsigned long tmp = 0;
|
||||
calculate_up_do_width_(des, scope, tmp);
|
||||
use_width = tmp;
|
||||
break;
|
||||
}
|
||||
case index_component_t::SEL_BIT:
|
||||
use_width = 1;
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
}
|
||||
const name_component_t&name_tail = path_.back();
|
||||
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
||||
if (!name_tail.index.empty())
|
||||
use_sel = name_tail.index.back().sel;
|
||||
|
||||
unsigned use_width = UINT_MAX;
|
||||
switch (use_sel) {
|
||||
case index_component_t::SEL_NONE:
|
||||
break;
|
||||
case index_component_t::SEL_PART:
|
||||
{ long msb, lsb;
|
||||
calculate_parts_(des, scope, msb, lsb);
|
||||
use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb));
|
||||
break;
|
||||
}
|
||||
case index_component_t::SEL_IDX_UP:
|
||||
case index_component_t::SEL_IDX_DO:
|
||||
{ unsigned long tmp = 0;
|
||||
calculate_up_do_width_(des, scope, tmp);
|
||||
use_width = tmp;
|
||||
break;
|
||||
}
|
||||
case index_component_t::SEL_BIT:
|
||||
use_width = 1;
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
}
|
||||
|
||||
if (use_width != UINT_MAX)
|
||||
return use_width;
|
||||
|
||||
// The width of a signal expression is the width of the signal.
|
||||
if (net != 0)
|
||||
return net->vector_width();
|
||||
|
||||
// The width of a parameter name is the width of the range for
|
||||
// the parameter name, if a range is declared. Otherwise, the
|
||||
// width is undefined.
|
||||
if (par != 0) {
|
||||
if (ex1) {
|
||||
ivl_assert(*this, ex2);
|
||||
const NetEConst*ex1_const = dynamic_cast<const NetEConst*> (ex1);
|
||||
const NetEConst*ex2_const = dynamic_cast<const NetEConst*> (ex2);
|
||||
ivl_assert(*this, ex1_const && ex2_const);
|
||||
|
||||
long msb = ex1_const->value().as_long();
|
||||
long lsb = ex2_const->value().as_long();
|
||||
if (msb >= lsb)
|
||||
return msb - lsb + 1;
|
||||
else
|
||||
return lsb - msb + 1;
|
||||
}
|
||||
|
||||
// This is a parameter. If it is sized (meaning it was
|
||||
// declared with range expresions) then the range
|
||||
// expressions would have been caught above. So if we
|
||||
// got there there we know this is an unsized constant.
|
||||
unsized_flag = true;
|
||||
return par->expr_width();
|
||||
}
|
||||
|
||||
return min;
|
||||
|
|
@ -2165,9 +2220,22 @@ unsigned PEUnary::test_width(Design*des, NetScope*scope,
|
|||
case 'N': // Reduction NOR (~|)
|
||||
case 'X': // Reduction NXOR (~^)
|
||||
return 1;
|
||||
default:
|
||||
return expr_->test_width(des, scope, min, lval, unsized_flag);
|
||||
}
|
||||
|
||||
unsigned test_wid = expr_->test_width(des, scope, min, lval, unsized_flag);
|
||||
switch (op_) {
|
||||
// For these operators, the act of padding to the
|
||||
// minimum width can have an important impact on the
|
||||
// calculation. So don't let the tested width be less
|
||||
// then the tested width.
|
||||
case '-':
|
||||
case '+':
|
||||
if (test_wid < min)
|
||||
test_wid = min;
|
||||
break;
|
||||
}
|
||||
|
||||
return test_wid;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
17
elaborate.cc
17
elaborate.cc
|
|
@ -91,7 +91,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
|||
return;
|
||||
}
|
||||
|
||||
assert(lval->pin_count() == 1);
|
||||
ivl_assert(*this, lval->pin_count() == 1);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: PGAssign: elaborated l-value"
|
||||
|
|
@ -99,9 +99,20 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
|||
<< ", type=" << lval->data_type() << endl;
|
||||
}
|
||||
|
||||
bool unsized_flag = false;
|
||||
unsigned 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 "
|
||||
<< "width is " << use_width
|
||||
<< ", min=" << lval->vector_width()
|
||||
<< ", unsized_flag=" << (unsized_flag?"true":"false") << endl;
|
||||
}
|
||||
|
||||
int expr_wid = unsized_flag? -1 : use_width;
|
||||
NetExpr*rval_expr = elab_and_eval(des, scope, pin(1),
|
||||
lval->vector_width(),
|
||||
lval->vector_width());
|
||||
expr_wid, lval->vector_width());
|
||||
|
||||
if (rval_expr == 0) {
|
||||
cerr << get_fileline() << ": error: Unable to elaborate r-value: "
|
||||
|
|
|
|||
Loading…
Reference in New Issue