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:
Cary R 2008-12-01 19:21:47 -08:00 committed by Stephen Williams
parent a84682e07d
commit 0abefc61fb
3 changed files with 63 additions and 32 deletions

View File

@ -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)) {
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
// vector, then do not bother with it. Return the
// signal itself.
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width())
return net;
// 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()) {
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)) {
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
// 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())
return net;
// 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()) {
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);

View File

@ -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);
select_width -= below_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()) {
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;
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.

View File

@ -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;
}