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,20 +5243,37 @@ 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);
// 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;
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;
}
rel_base = net->sig()->sb_to_idx(prefix_indices, lsv) + offset;
}
long rel_base = net->sig()->sb_to_idx(prefix_indices, lsv);
rel_base += offset;
// If the part select covers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
@ -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);
// 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;
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;
}
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,21 +938,45 @@ 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);
// We want the last range, which is where we work.
const netrange_t&rng = packed.back();
if (((rng.get_msb() < rng.get_lsb()) &&
use_sel == index_component_t::SEL_IDX_UP) ||
((rng.get_msb() > rng.get_lsb()) &&
use_sel == index_component_t::SEL_IDX_DO)) {
offset = -wid + 1;
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()) &&
use_sel == index_component_t::SEL_IDX_UP) ||
((rng.get_msb() > rng.get_lsb()) &&
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,49 +262,74 @@ 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 (index_tail.sel == index_component_t::SEL_IDX_UP)
lidx = sig->sb_to_idx(prefix_indices, midx_val+wid-1);
else
lidx = sig->sb_to_idx(prefix_indices, midx_val-wid+1);
if (midx < lidx) {
long tmpx = midx;
midx = lidx;
lidx = tmpx;
}
/* Warn about an indexed part select that is out of range. */
if (warn_ob_select && (lidx < 0)) {
cerr << get_fileline() << ": warning: " << sig->name();
if (sig->unpacked_dimensions() > 0) cerr << "[]";
cerr << "[" << midx_val;
if (index_tail.sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
if (moff > loff) {
lidx = loff;
midx = moff + mwid - 1;
} else {
cerr << "-:";
lidx = moff;
midx = loff + lwid - 1;
}
cerr << wid << "] is selecting before vector." << endl;
}
if (warn_ob_select && (midx >= (long)sig->vector_width())) {
cerr << get_fileline() << ": warning: " << sig->name();
if (sig->unpacked_dimensions() > 0) {
cerr << "[]";
}
cerr << "[" << midx_val;
if (index_tail.sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
} else {
cerr << "-:";
}
cerr << wid << "] is selecting after vector." << endl;
}
} else {
midx = sig->sb_to_idx(prefix_indices, midx_val);
/* This is completely out side the signal so just skip it. */
if (lidx >= (long)sig->vector_width() || midx < 0) {
return false;
if (index_tail.sel == index_component_t::SEL_IDX_UP)
lidx = sig->sb_to_idx(prefix_indices, midx_val+wid-1);
else
lidx = sig->sb_to_idx(prefix_indices, midx_val-wid+1);
if (midx < lidx) {
long tmpx = midx;
midx = lidx;
lidx = tmpx;
}
/* Warn about an indexed part select that is out of range. */
if (warn_ob_select && (lidx < 0)) {
cerr << get_fileline() << ": warning: " << sig->name();
if (sig->unpacked_dimensions() > 0) cerr << "[]";
cerr << "[" << midx_val;
if (index_tail.sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
} else {
cerr << "-:";
}
cerr << wid << "] is selecting before vector." << endl;
}
if (warn_ob_select && (midx >= (long)sig->vector_width())) {
cerr << get_fileline() << ": warning: " << sig->name();
if (sig->unpacked_dimensions() > 0) {
cerr << "[]";
}
cerr << "[" << midx_val;
if (index_tail.sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
} else {
cerr << "-:";
}
cerr << wid << "] is selecting after vector." << endl;
}
/* This is completely out side the signal so just skip it. */
if (lidx >= (long)sig->vector_width() || midx < 0) {
return false;
}
}
break;