Allow part selects to fall off the ends of the selected identifier
Part selects to signals are allowed to be off the ends of the signal itself. The bits that are beyond the vector return X. This may mean creating constant X bits on one or both ends of the result.
This commit is contained in:
parent
f256dfe16e
commit
b31124983a
93
elab_expr.cc
93
elab_expr.cc
|
|
@ -1370,8 +1370,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
|
||||||
// Special case: The index is out of range, so the value
|
// Special case: The index is out of range, so the value
|
||||||
// of this expression is a 'bx vector the width of a word.
|
// of this expression is a 'bx vector the width of a word.
|
||||||
if (!net->array_index_is_valid(addr)) {
|
if (!net->array_index_is_valid(addr)) {
|
||||||
verinum xxx (verinum::Vx, net->vector_width());
|
NetEConst*resx = make_const_x(net->vector_width());
|
||||||
NetEConst*resx = new NetEConst(xxx);
|
|
||||||
resx->set_line(*this);
|
resx->set_line(*this);
|
||||||
delete word_index;
|
delete word_index;
|
||||||
return resx;
|
return resx;
|
||||||
|
|
@ -1437,16 +1436,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||||
negative values. However, the width that they represent is
|
negative values. However, the width that they represent is
|
||||||
unsigned. Remember that any order is possible,
|
unsigned. Remember that any order is possible,
|
||||||
i.e., [1:0], [-4:6], etc. */
|
i.e., [1:0], [-4:6], etc. */
|
||||||
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
|
unsigned long wid = 1 + labs(msv-lsv);
|
||||||
if (wid > net->vector_width()) {
|
|
||||||
cerr << get_fileline() << ": error: part select ["
|
|
||||||
<< msv << ":" << lsv << "] out of range." << endl;
|
|
||||||
des->errors += 1;
|
|
||||||
//delete lsn;
|
|
||||||
//delete msn;
|
|
||||||
return net;
|
|
||||||
}
|
|
||||||
ivl_assert(*this, wid <= net->vector_width());
|
|
||||||
|
|
||||||
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
|
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
|
||||||
cerr << get_fileline() << ": error: part select ["
|
cerr << get_fileline() << ": error: part select ["
|
||||||
|
|
@ -1457,27 +1447,79 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||||
return net;
|
return net;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long sb_lsb = net->sig()->sb_to_idx(lsv);
|
||||||
if (net->sig()->sb_to_idx(msv) >= (signed) net->vector_width()) {
|
long sb_msb = net->sig()->sb_to_idx(msv);
|
||||||
cerr << get_fileline() << ": error: part select ["
|
|
||||||
<< msv << ":" << lsv << "] out of range." << endl;
|
|
||||||
des->errors += 1;
|
|
||||||
//delete lsn;
|
|
||||||
//delete msn;
|
|
||||||
return net;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the part select covers exactly the entire
|
// If the part select covers exactly the entire
|
||||||
// vector, then do not bother with it. Return the
|
// vector, then do not bother with it. Return the
|
||||||
// signal itself.
|
// signal itself.
|
||||||
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width())
|
if (sb_lsb == 0 && wid == net->vector_width())
|
||||||
return net;
|
return net;
|
||||||
|
|
||||||
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
|
// If the part select covers NONE of the vector, then return a
|
||||||
|
// constant X.
|
||||||
|
|
||||||
|
if ((sb_lsb >= (signed) net->vector_width()) || (sb_msb < 0)) {
|
||||||
|
NetEConst*tmp = make_const_x(wid);
|
||||||
|
tmp->set_line(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the part select is entirely within the vector, then make
|
||||||
|
// a simple part select.
|
||||||
|
if (sb_lsb >= 0 && sb_msb < (signed)net->vector_width()) {
|
||||||
|
NetExpr*ex = new NetEConst(verinum(sb_lsb));
|
||||||
NetESelect*ss = new NetESelect(net, ex, wid);
|
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||||
ss->set_line(*this);
|
ss->set_line(*this);
|
||||||
|
|
||||||
return ss;
|
return ss;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now the hard stuff. The part select is falling off at least
|
||||||
|
// one end. We're going to need a NetEConcat to mix the
|
||||||
|
// selection with overrun.
|
||||||
|
|
||||||
|
NetEConst*bot = 0;
|
||||||
|
if (sb_lsb < 0) {
|
||||||
|
bot = make_const_x( 0-sb_lsb );
|
||||||
|
bot->set_line(*this);
|
||||||
|
sb_lsb = 0;
|
||||||
|
}
|
||||||
|
NetEConst*top = 0;
|
||||||
|
if (sb_msb >= (signed)net->vector_width()) {
|
||||||
|
top = make_const_x( 1+sb_msb-net->vector_width() );
|
||||||
|
top->set_line(*this);
|
||||||
|
sb_msb = net->vector_width()-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned concat_count = 1;
|
||||||
|
if (bot) concat_count += 1;
|
||||||
|
if (top) concat_count += 1;
|
||||||
|
|
||||||
|
NetEConcat*concat = new NetEConcat(concat_count);
|
||||||
|
concat->set_line(*this);
|
||||||
|
|
||||||
|
if (bot) {
|
||||||
|
concat_count -= 1;
|
||||||
|
concat->set(concat_count, bot);
|
||||||
|
}
|
||||||
|
if (sb_lsb == 0 && sb_msb+1 == (signed)net->vector_width()) {
|
||||||
|
concat_count -= 1;
|
||||||
|
concat->set(concat_count, net);
|
||||||
|
} else {
|
||||||
|
NetExpr*ex = new NetEConst(verinum(sb_lsb));
|
||||||
|
ex->set_line(*this);
|
||||||
|
NetESelect*ss = new NetESelect(net, ex, 1+sb_msb-sb_lsb);
|
||||||
|
ss->set_line(*this);
|
||||||
|
concat_count -= 1;
|
||||||
|
concat->set(concat_count, ss);
|
||||||
|
}
|
||||||
|
if (top) {
|
||||||
|
concat_count -= 1;
|
||||||
|
concat->set(concat_count, top);
|
||||||
|
}
|
||||||
|
ivl_assert(*this, concat_count==0);
|
||||||
|
|
||||||
|
return concat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1618,8 +1660,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||||
/* The bit select is out of range of the
|
/* The bit select is out of range of the
|
||||||
vector. This is legal, but returns a
|
vector. This is legal, but returns a
|
||||||
constant 1'bx value. */
|
constant 1'bx value. */
|
||||||
verinum x (verinum::Vx);
|
NetEConst*tmp = make_const_x(1);
|
||||||
NetEConst*tmp = new NetEConst(x);
|
|
||||||
tmp->set_line(*this);
|
tmp->set_line(*this);
|
||||||
|
|
||||||
cerr << get_fileline() << ": warning: Bit select ["
|
cerr << get_fileline() << ": warning: Bit select ["
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,13 @@ NetExpr* make_sub_expr(long val, NetExpr*expr)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetEConst* make_const_x(unsigned long wid)
|
||||||
|
{
|
||||||
|
verinum xxx (verinum::Vx, wid);
|
||||||
|
NetEConst*resx = new NetEConst(xxx);
|
||||||
|
return resx;
|
||||||
|
}
|
||||||
|
|
||||||
NetExpr* condition_reduce(NetExpr*expr)
|
NetExpr* condition_reduce(NetExpr*expr)
|
||||||
{
|
{
|
||||||
if (expr->expr_width() == 1)
|
if (expr->expr_width() == 1)
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,11 @@ extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
|
||||||
extern NetExpr*make_add_expr(NetExpr*expr, long val);
|
extern NetExpr*make_add_expr(NetExpr*expr, long val);
|
||||||
extern NetExpr*make_sub_expr(long val, NetExpr*expr);
|
extern NetExpr*make_sub_expr(long val, NetExpr*expr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make a NetEConst object that contains only X bits.
|
||||||
|
*/
|
||||||
|
extern NetEConst*make_const_x(unsigned long wid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In some cases the lval is accessible as a pointer to the head of
|
* In some cases the lval is accessible as a pointer to the head of
|
||||||
* a list of NetAssign_ objects. This function returns the width of
|
* a list of NetAssign_ objects. This function returns the width of
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue