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
40
elab_expr.cc
40
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
|
||||
// part select.
|
||||
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
||||
NetExpr*ex;
|
||||
if (base_c->value().is_defined()) {
|
||||
long lsv = base_c->value().as_long();
|
||||
|
||||
// If the part select covers exactly the entire
|
||||
// vector, then do not bother with it. Return the
|
||||
// signal itself.
|
||||
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width())
|
||||
if (net->sig()->sb_to_idx(lsv) == 0 &&
|
||||
wid == net->vector_width()) {
|
||||
delete base;
|
||||
return net;
|
||||
}
|
||||
|
||||
// Otherwise, make a part select that covers the right range.
|
||||
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
|
||||
// Otherwise, make a part select that covers the right
|
||||
// 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);
|
||||
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,
|
||||
NetESignal*net, NetScope*found_in)const
|
||||
{
|
||||
const name_component_t&name_tail = path_.back();
|
||||
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);
|
||||
NetExpr*base = calculate_up_do_base_(des, scope);
|
||||
|
||||
unsigned long wid = 0;
|
||||
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
|
||||
// part select.
|
||||
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
||||
NetExpr*ex;
|
||||
if (base_c->value().is_defined()) {
|
||||
long lsv = base_c->value().as_long();
|
||||
|
||||
// If the part select covers exactly the entire
|
||||
// vector, then do not bother with it. Return the
|
||||
// signal itself.
|
||||
if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) &&
|
||||
wid == net->vector_width())
|
||||
wid == net->vector_width()) {
|
||||
delete base;
|
||||
return net;
|
||||
}
|
||||
|
||||
// Otherwise, make a part select that covers the right range.
|
||||
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)-wid+1));
|
||||
// Otherwise, make a part select that covers the right
|
||||
// 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);
|
||||
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.
|
||||
if (NetEConst*base_const = dynamic_cast<NetEConst*>(base_)) {
|
||||
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();
|
||||
unsigned select_width = expr_width();
|
||||
|
||||
// Any below X bits?
|
||||
NetNet*below = 0;
|
||||
if (base_val < 0) {
|
||||
unsigned below_width = abs(base_val);
|
||||
base_val = 0;
|
||||
ivl_assert(*this, below_width < select_width);
|
||||
if (below_width > select_width) {
|
||||
below_width = select_width;
|
||||
select_width = 0;
|
||||
} else {
|
||||
select_width -= below_width;
|
||||
}
|
||||
|
||||
below = make_const_x(des, scope, below_width);
|
||||
below->set_line(*this);
|
||||
// All the selected bits are below the signal.
|
||||
if (select_width == 0) return below;
|
||||
}
|
||||
|
||||
// Any above bits?
|
||||
NetNet*above = 0;
|
||||
if ((unsigned)base_val+select_width > sub->vector_width()) {
|
||||
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;
|
||||
|
||||
above = make_const_x(des, scope, above_width);
|
||||
above->set_line(*this);
|
||||
// All the selected bits are above the signal.
|
||||
if (select_width == 0) return above;
|
||||
}
|
||||
|
||||
// Make the make part select.
|
||||
|
|
|
|||
|
|
@ -315,9 +315,10 @@ verinum::verinum(int64_t that)
|
|||
{
|
||||
int64_t tmp;
|
||||
|
||||
tmp = that/2;
|
||||
if (that < 0) tmp = (that+1)/2;
|
||||
else tmp = that/2;
|
||||
nbits_ = 1;
|
||||
while ((tmp != 0) && (tmp != -1)) {
|
||||
while (tmp != 0) {
|
||||
nbits_ += 1;
|
||||
tmp /= 2;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue