Fix out of range indexed part selects and negative verinum width calc.
This patch fixes fully out of range constant indexed part selects to just return 'bx. It also adds support for constant undefined base values which also just return 'bx. A bug in the bit width calculation when building an unsized, signed negative integer value was also fixed (-3 needs 3 bits not 2, etc.)
This commit is contained in:
parent
a84682e07d
commit
0abefc61fb
62
elab_expr.cc
62
elab_expr.cc
|
|
@ -2526,16 +2526,26 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
|
||||||
// well. In this case it can be converted to a conventional
|
// well. In this case it can be converted to a conventional
|
||||||
// part select.
|
// part select.
|
||||||
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
||||||
long lsv = base_c->value().as_long();
|
NetExpr*ex;
|
||||||
|
if (base_c->value().is_defined()) {
|
||||||
|
long lsv = base_c->value().as_long();
|
||||||
|
|
||||||
// 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 (net->sig()->sb_to_idx(lsv) == 0 &&
|
||||||
return net;
|
wid == net->vector_width()) {
|
||||||
|
delete base;
|
||||||
|
return net;
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, make a part select that covers the right range.
|
// Otherwise, make a part select that covers the right
|
||||||
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
|
// range.
|
||||||
|
ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
|
||||||
|
} else {
|
||||||
|
// Return 'bx for an undefined base.
|
||||||
|
ex = new NetEConst(verinum(verinum::Vx, 1, false));
|
||||||
|
}
|
||||||
NetESelect*ss = new NetESelect(net, ex, wid);
|
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||||
ss->set_line(*this);
|
ss->set_line(*this);
|
||||||
|
|
||||||
|
|
@ -2569,14 +2579,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
|
||||||
NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
|
NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
|
||||||
NetESignal*net, NetScope*found_in)const
|
NetESignal*net, NetScope*found_in)const
|
||||||
{
|
{
|
||||||
const name_component_t&name_tail = path_.back();
|
NetExpr*base = calculate_up_do_base_(des, scope);
|
||||||
ivl_assert(*this, ! name_tail.index.empty());
|
|
||||||
|
|
||||||
const index_component_t&index_tail = name_tail.index.back();
|
|
||||||
ivl_assert(*this, index_tail.lsb != 0);
|
|
||||||
ivl_assert(*this, index_tail.msb != 0);
|
|
||||||
|
|
||||||
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
|
|
||||||
|
|
||||||
unsigned long wid = 0;
|
unsigned long wid = 0;
|
||||||
calculate_up_do_width_(des, scope, wid);
|
calculate_up_do_width_(des, scope, wid);
|
||||||
|
|
@ -2585,17 +2588,26 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
|
||||||
// well. In this case it can be converted to a conventional
|
// well. In this case it can be converted to a conventional
|
||||||
// part select.
|
// part select.
|
||||||
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
||||||
long lsv = base_c->value().as_long();
|
NetExpr*ex;
|
||||||
|
if (base_c->value().is_defined()) {
|
||||||
|
long lsv = base_c->value().as_long();
|
||||||
|
|
||||||
// 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) == (signed) (wid-1) &&
|
if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) &&
|
||||||
wid == net->vector_width())
|
wid == net->vector_width()) {
|
||||||
return net;
|
delete base;
|
||||||
|
return net;
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, make a part select that covers the right range.
|
// Otherwise, make a part select that covers the right
|
||||||
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)-wid+1));
|
// range.
|
||||||
|
ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)-wid+1));
|
||||||
|
} else {
|
||||||
|
// Return 'bx for an undefined base.
|
||||||
|
ex = new NetEConst(verinum(verinum::Vx, 1, false));
|
||||||
|
}
|
||||||
NetESelect*ss = new NetESelect(net, ex, wid);
|
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||||
ss->set_line(*this);
|
ss->set_line(*this);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -974,31 +974,49 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope)
|
||||||
// it is constant. In this case we can generate fixed part selects.
|
// it is constant. In this case we can generate fixed part selects.
|
||||||
if (NetEConst*base_const = dynamic_cast<NetEConst*>(base_)) {
|
if (NetEConst*base_const = dynamic_cast<NetEConst*>(base_)) {
|
||||||
verinum base_tmp = base_const->value();
|
verinum base_tmp = base_const->value();
|
||||||
ivl_assert(*this, base_tmp.is_defined());
|
unsigned select_width = expr_width();
|
||||||
|
|
||||||
|
// Return 'bx for a constant undefined selections.
|
||||||
|
if (!base_tmp.is_defined()) {
|
||||||
|
NetNet*result = make_const_x(des, scope, select_width);
|
||||||
|
result->set_line(*this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
long base_val = base_tmp.as_long();
|
long base_val = base_tmp.as_long();
|
||||||
unsigned select_width = expr_width();
|
|
||||||
|
|
||||||
// Any below X bits?
|
// Any below X bits?
|
||||||
NetNet*below = 0;
|
NetNet*below = 0;
|
||||||
if (base_val < 0) {
|
if (base_val < 0) {
|
||||||
unsigned below_width = abs(base_val);
|
unsigned below_width = abs(base_val);
|
||||||
base_val = 0;
|
base_val = 0;
|
||||||
ivl_assert(*this, below_width < select_width);
|
if (below_width > select_width) {
|
||||||
select_width -= below_width;
|
below_width = select_width;
|
||||||
|
select_width = 0;
|
||||||
|
} else {
|
||||||
|
select_width -= below_width;
|
||||||
|
}
|
||||||
|
|
||||||
below = make_const_x(des, scope, below_width);
|
below = make_const_x(des, scope, below_width);
|
||||||
below->set_line(*this);
|
below->set_line(*this);
|
||||||
|
// All the selected bits are below the signal.
|
||||||
|
if (select_width == 0) return below;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any above bits?
|
// Any above bits?
|
||||||
NetNet*above = 0;
|
NetNet*above = 0;
|
||||||
if ((unsigned)base_val+select_width > sub->vector_width()) {
|
if ((unsigned)base_val+select_width > sub->vector_width()) {
|
||||||
select_width = sub->vector_width() - base_val;
|
if (base_val > (long)sub->vector_width()) {
|
||||||
|
select_width = 0;
|
||||||
|
} else {
|
||||||
|
select_width = sub->vector_width() - base_val;
|
||||||
|
}
|
||||||
unsigned above_width = expr_width() - select_width;
|
unsigned above_width = expr_width() - select_width;
|
||||||
|
|
||||||
above = make_const_x(des, scope, above_width);
|
above = make_const_x(des, scope, above_width);
|
||||||
above->set_line(*this);
|
above->set_line(*this);
|
||||||
|
// All the selected bits are above the signal.
|
||||||
|
if (select_width == 0) return above;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the make part select.
|
// Make the make part select.
|
||||||
|
|
|
||||||
|
|
@ -315,9 +315,10 @@ verinum::verinum(int64_t that)
|
||||||
{
|
{
|
||||||
int64_t tmp;
|
int64_t tmp;
|
||||||
|
|
||||||
tmp = that/2;
|
if (that < 0) tmp = (that+1)/2;
|
||||||
|
else tmp = that/2;
|
||||||
nbits_ = 1;
|
nbits_ = 1;
|
||||||
while ((tmp != 0) && (tmp != -1)) {
|
while (tmp != 0) {
|
||||||
nbits_ += 1;
|
nbits_ += 1;
|
||||||
tmp /= 2;
|
tmp /= 2;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue