From c0c46dc173ace4f0f0e1d93bba104c81e56b048a Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 20 Apr 2021 21:29:00 +0100 Subject: [PATCH] Support indexed part selects that index sub-arrays (issue #497) (cherry picked from commit 4af830187e1cd3837d3152e5de8f8febaa05cfef) --- elab_expr.cc | 72 ++++++++++++++++++++++++++---------- elab_lval.cc | 44 +++++++++++++++++----- elab_net.cc | 101 ++++++++++++++++++++++++++++++++------------------- 3 files changed, 150 insertions(+), 67 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index b9dd81817..a9f8b3627 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -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&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&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 diff --git a/elab_lval.cc b/elab_lval.cc index 14f0aa227..3083a2297 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -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&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)); diff --git a/elab_net.cc b/elab_net.cc index 55bdbce9c..8d96ec44b 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -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;