Support indexed part selects that index sub-arrays (issue #497)

(cherry picked from commit 4af830187e)
This commit is contained in:
Martin Whitaker 2021-04-20 21:29:00 +01:00
parent cccf36d76f
commit c0c46dc173
3 changed files with 150 additions and 67 deletions

View File

@ -5243,19 +5243,36 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
NetExpr*ex;
if (base_c->value().is_defined()) {
long lsv = base_c->value().as_long();
long offset = 0;
long rel_base = 0;
// Get the signal range.
const vector<netrange_t>&packed = net->sig()->packed_dims();
ivl_assert(*this, packed.size() == prefix_indices.size()+1);
if (prefix_indices.size()+1 < net->sig()->packed_dims().size()) {
// Here we are selecting one or more sub-arrays.
// Make this work by finding the indexed sub-arrays and
// creating a generated slice that spans the whole range.
long loff, moff;
unsigned long lwid, mwid;
bool lrc;
lrc = net->sig()->sb_to_slice(prefix_indices, lsv, moff, mwid);
ivl_assert(*this, lrc);
lrc = net->sig()->sb_to_slice(prefix_indices, lsv+(wid/mwid)-1, loff, lwid);
ivl_assert(*this, lrc);
ivl_assert(*this, lwid == mwid);
if (moff > loff) {
rel_base = loff;
} else {
rel_base = moff;
}
} else {
long offset = 0;
// We want the last range, which is where we work.
const netrange_t&rng = packed.back();
if (rng.get_msb() < rng.get_lsb()) {
offset = -wid + 1;
}
long rel_base = net->sig()->sb_to_idx(prefix_indices, lsv);
rel_base += offset;
rel_base = net->sig()->sb_to_idx(prefix_indices, lsv) + offset;
}
// If the part select covers exactly the entire
// vector, then do not bother with it. Return the
@ -5347,19 +5364,36 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
NetExpr*ex;
if (base_c->value().is_defined()) {
long lsv = base_c->value().as_long();
long offset = 0;
long rel_base = 0;
// Get the signal range.
const vector<netrange_t>&packed = net->sig()->packed_dims();
ivl_assert(*this, packed.size() == prefix_indices.size()+1);
if (prefix_indices.size()+1 < net->sig()->packed_dims().size()) {
// Here we are selecting one or more sub-arrays.
// Make this work by finding the indexed sub-arrays and
// creating a generated slice that spans the whole range.
long loff, moff;
unsigned long lwid, mwid;
bool lrc;
lrc = net->sig()->sb_to_slice(prefix_indices, lsv, moff, mwid);
ivl_assert(*this, lrc);
lrc = net->sig()->sb_to_slice(prefix_indices, lsv-(wid/mwid)+1, loff, lwid);
ivl_assert(*this, lrc);
ivl_assert(*this, lwid == mwid);
if (moff > loff) {
rel_base = loff;
} else {
rel_base = moff;
}
} else {
long offset = 0;
// We want the last range, which is where we work.
const netrange_t&rng = packed.back();
if (rng.get_msb() > rng.get_lsb()) {
offset = -wid + 1;
}
long rel_base = net->sig()->sb_to_idx(prefix_indices, lsv);
rel_base += offset;
rel_base = net->sig()->sb_to_idx(prefix_indices, lsv) + offset;
}
// If the part select covers exactly the entire
// vector, then do not bother with it. Return the

View File

@ -938,11 +938,34 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
// we will handle it in the code generator.
if (base_c->value().is_defined()) {
long lsv = base_c->value().as_long();
long offset = 0;
long rel_base = 0;
// Get the signal range.
const vector<netrange_t>&packed = reg->packed_dims();
ivl_assert(*this, packed.size() == prefix_indices.size()+1);
if (prefix_indices.size()+1 < reg->packed_dims().size()) {
// Here we are selecting one or more sub-arrays.
// Make this work by finding the indexed sub-arrays and
// creating a generated slice that spans the whole range.
long loff, moff;
unsigned long lwid, mwid;
bool lrc;
lrc = reg->sb_to_slice(prefix_indices, lsv, moff, mwid);
ivl_assert(*this, lrc);
if (use_sel == index_component_t::SEL_IDX_UP)
lrc = reg->sb_to_slice(prefix_indices, lsv+wid-1, loff, lwid);
else
lrc = reg->sb_to_slice(prefix_indices, lsv-wid+1, loff, lwid);
ivl_assert(*this, lrc);
ivl_assert(*this, lwid == mwid);
if (moff > loff) {
rel_base = loff;
wid = moff + mwid - loff;
} else {
rel_base = moff;
wid = loff + lwid - moff;
}
} else {
long offset = 0;
// We want the last range, which is where we work.
const netrange_t&rng = packed.back();
if (((rng.get_msb() < rng.get_lsb()) &&
@ -951,8 +974,9 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
use_sel == index_component_t::SEL_IDX_DO)) {
offset = -wid + 1;
}
rel_base = reg->sb_to_idx(prefix_indices,lsv) + offset;
}
delete base;
long rel_base = reg->sb_to_idx(prefix_indices,lsv) + offset;
/* If we cover the entire lvalue just skip the select. */
if (rel_base == 0 && wid == reg->vector_width()) return true;
base = new NetEConst(verinum(rel_base));

View File

@ -262,8 +262,32 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
}
long midx_val = tmp->value().as_long();
midx = sig->sb_to_idx(prefix_indices, midx_val);
delete tmp_ex;
if (prefix_indices.size()+1 < sig->packed_dims().size()) {
// Here we are selecting one or more sub-arrays.
// Make this work by finding the indexed sub-arrays and
// creating a generated slice that spans the whole range.
long loff, moff;
unsigned long lwid, mwid;
bool lrc;
lrc = sig->sb_to_slice(prefix_indices, midx_val, moff, mwid);
ivl_assert(*this, lrc);
if (index_tail.sel == index_component_t::SEL_IDX_UP)
lrc = sig->sb_to_slice(prefix_indices, midx_val+wid-1, loff, lwid);
else
lrc = sig->sb_to_slice(prefix_indices, midx_val-wid+1, loff, lwid);
ivl_assert(*this, lrc);
ivl_assert(*this, lwid == mwid);
if (moff > loff) {
lidx = loff;
midx = moff + mwid - 1;
} else {
lidx = moff;
midx = loff + lwid - 1;
}
} else {
midx = sig->sb_to_idx(prefix_indices, midx_val);
if (index_tail.sel == index_component_t::SEL_IDX_UP)
lidx = sig->sb_to_idx(prefix_indices, midx_val+wid-1);
@ -306,6 +330,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
if (lidx >= (long)sig->vector_width() || midx < 0) {
return false;
}
}
break;
}