Consolidate net up/down part select

The methods for handling up and down part select are nearly identical
and only differ in a hand full of lines.

Consolidate them into a single method to remove the duplicated code.
This makes it easier to maintain the code and add future changes.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2021-12-30 21:47:19 +01:00
parent 37dca4a016
commit f77670a706
2 changed files with 37 additions and 201 deletions

15
PExpr.h
View File

@ -511,16 +511,11 @@ class PEIdent : public PExpr {
NetESignal*net,
NetScope*found,
unsigned expr_wid) const;
NetExpr*elaborate_expr_net_idx_up_(Design*des,
NetScope*scope,
NetESignal*net,
NetScope*found,
bool need_const) const;
NetExpr*elaborate_expr_net_idx_do_(Design*des,
NetScope*scope,
NetESignal*net,
NetScope*found,
bool need_const) const;
NetExpr*elaborate_expr_net_idx_up_do_(Design*des,
NetScope*scope,
NetESignal*net,
NetScope*found,
bool up, bool need_const) const;
NetExpr*elaborate_expr_net_bit_(Design*des,
NetScope*scope,
NetESignal*net,

View File

@ -5721,12 +5721,12 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
expr_wid);
if (word_sel == index_component_t::SEL_IDX_UP)
return elaborate_expr_net_idx_up_(des, scope, res, found_in,
need_const);
return elaborate_expr_net_idx_up_do_(des, scope, res, found_in,
true, need_const);
if (word_sel == index_component_t::SEL_IDX_DO)
return elaborate_expr_net_idx_do_(des, scope, res, found_in,
need_const);
return elaborate_expr_net_idx_up_do_(des, scope, res, found_in,
false, need_const);
if (word_sel == index_component_t::SEL_BIT)
return elaborate_expr_net_bit_(des, scope, res, found_in,
@ -5880,10 +5880,11 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
}
/*
* Part select indexed up, i.e. net[<m> +: <l>]
* Part select indexed up or down, i.e. net[<m> +: <l>]
*/
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
NetExpr* PEIdent::elaborate_expr_net_idx_up_do_(Design*des, NetScope*scope,
NetESignal*net, NetScope*,
bool up,
bool need_const) const
{
if (net->sig()->data_type() == IVL_VT_STRING) {
@ -5902,13 +5903,15 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
if (!base)
return nullptr;
// Use the part select width already calculated by test_width().
unsigned long wid = min_width_;
const char *op = up ? "+" : "-";
if (base->expr_type() == IVL_VT_REAL) {
cerr << get_fileline() << ": error: Indexed part select base "
"expression for " << net->sig()->name() << "[" << *base
<< "+:" << wid << "] cannot be a real value." << endl;
<< op << ":" << wid << "] cannot be a real value." << endl;
des->errors += 1;
return 0;
}
@ -5919,13 +5922,13 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
if (const NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
NetExpr*ex;
if (base_c->value().is_defined()) {
long lsv = base_c->value().as_long();
long msv = base_c->value().as_long();
long rel_base = 0;
// Check whether an unsigned base fits in a 32 bit int.
// This ensures correct results for the vlog95 target, and
// for the vvp target on LLP64 platforms (Microsoft Windows).
if (!base_c->has_sign() && (int32_t)lsv < 0) {
if (!base_c->has_sign() && (int32_t)msv < 0) {
// Return 'bx for a wrapped around base.
ex = new NetEConst(verinum(verinum::Vx, wid, true));
ex->set_line(*this);
@ -5933,7 +5936,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
if (warn_ob_select) {
cerr << get_fileline() << ": warning: " << net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << (unsigned long)lsv << "+:" << wid
cerr << "[" << (unsigned long)msv << op << ":" << wid
<< "] is always outside vector." << endl;
}
return ex;
@ -5949,12 +5952,17 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
ivl_assert(*this, swid > 0);
long loff, moff;
unsigned long lwid, mwid;
long lsv = msv;
if (up)
lsv += (wid/swid)-1;
else
lsv -= (wid/swid)-1;
bool lrc, mrc;
mrc = net->sig()->sb_to_slice(prefix_indices, lsv, moff, mwid);
lrc = net->sig()->sb_to_slice(prefix_indices, lsv+(wid/swid)-1, loff, lwid);
mrc = net->sig()->sb_to_slice(prefix_indices, msv, moff, mwid);
lrc = net->sig()->sb_to_slice(prefix_indices, lsv, loff, lwid);
if (!mrc || !lrc) {
cerr << get_fileline() << ": error: ";
cerr << "Part-select [" << lsv << "+:" << (wid/swid);
cerr << "Part-select [" << msv << op << ":" << (wid/swid);
cerr << "] exceeds the declared bounds for ";
cerr << net->sig()->name();
if (net->sig()->unpacked_dimensions() > 0) cerr << "[]";
@ -5974,10 +5982,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
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()) {
if ((rng.get_msb() > rng.get_lsb()) ^ up) {
offset = -wid + 1;
}
rel_base = net->sig()->sb_to_idx(prefix_indices, lsv) + offset;
rel_base = net->sig()->sb_to_idx(prefix_indices, msv) + offset;
}
// If the part select covers exactly the entire
@ -5988,7 +5996,6 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
net->cast_signed(false);
return net;
}
// Otherwise, make a part select that covers the right
// range.
ex = new NetEConst(verinum(rel_base));
@ -5997,14 +6004,14 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
cerr << get_fileline() << ": warning: "
<< net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << lsv << "+:" << wid
cerr << "[" << msv << op << ":" << wid
<< "] is selecting before vector." << endl;
}
if (rel_base + wid > net->vector_width()) {
cerr << get_fileline() << ": warning: "
<< net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << lsv << "+:" << wid
cerr << "[" << msv << op << ":" << wid
<< "] is selecting after vector." << endl;
}
}
@ -6016,7 +6023,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
if (warn_ob_select) {
cerr << get_fileline() << ": warning: " << net->name();
if (net->word_index()) cerr << "[]";
cerr << "['bx+:" << wid
cerr << "['bx" << op << ":" << wid
<< "] is always outside vector." << endl;
}
return ex;
@ -6033,175 +6040,9 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
// Convert the non-constant part select index expression into
// an expression that returns a canonical base.
base = normalize_variable_part_base(prefix_indices, base, net->sig(), wid, true);
base = normalize_variable_part_base(prefix_indices, base, net->sig(), wid, up);
NetESelect*ss = new NetESelect(net, base, wid, IVL_SEL_IDX_UP);
ss->set_line(*this);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Elaborate part "
<< "select base="<< *base << ", wid="<< wid << endl;
}
return ss;
}
/*
* Part select indexed down, i.e. net[<m> -: <l>]
*/
NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
NetESignal*net, NetScope*,
bool need_const) const
{
if (net->sig()->data_type() == IVL_VT_STRING) {
cerr << get_fileline() << ": error: Cannot take the index part "
"select of a string ('" << net->name() << "')." << endl;
des->errors += 1;
return 0;
}
list<long>prefix_indices;
bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices);
if (!rc)
return 0;
NetExpr*base = calculate_up_do_base_(des, scope, need_const);
if (!base)
return nullptr;
// Use the part select width already calculated by test_width().
unsigned long wid = min_width_;
if (base->expr_type() == IVL_VT_REAL) {
cerr << get_fileline() << ": error: Indexed part select base "
"expression for " << net->sig()->name() << "[" << *base
<< "-:" << wid << "] cannot be a real value." << endl;
des->errors += 1;
return 0;
}
// Handle the special case that the base is constant as
// well. In this case it can be converted to a conventional
// part select.
if (const NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
NetExpr*ex;
if (base_c->value().is_defined()) {
long lsv = base_c->value().as_long();
long rel_base = 0;
// Check whether an unsigned base fits in a 32 bit int.
// This ensures correct results for the vlog95 target, and
// for the vvp target on LLP64 platforms (Microsoft Windows).
if (!base_c->has_sign() && (int32_t)lsv < 0) {
// Return 'bx for a wrapped around base.
ex = new NetEConst(verinum(verinum::Vx, wid, true));
ex->set_line(*this);
delete base;
if (warn_ob_select) {
cerr << get_fileline() << ": warning: " << net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << (unsigned long)lsv << "-:" << wid
<< "] is always outside vector." << endl;
}
return ex;
}
// Get the signal range.
const netranges_t&packed = net->sig()->packed_dims();
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.
unsigned long swid = net->sig()->slice_width(prefix_indices.size()+1);
ivl_assert(*this, swid > 0);
long loff, moff;
unsigned long lwid, mwid;
bool lrc, mrc;
mrc = net->sig()->sb_to_slice(prefix_indices, lsv, moff, mwid);
lrc = net->sig()->sb_to_slice(prefix_indices, lsv-(wid/swid)+1, loff, lwid);
if (!mrc || !lrc) {
cerr << get_fileline() << ": error: ";
cerr << "Part-select [" << lsv << "-:" << (wid/swid);
cerr << "] exceeds the declared bounds for ";
cerr << net->sig()->name();
if (net->sig()->unpacked_dimensions() > 0) cerr << "[]";
cerr << "." << endl;
des->errors += 1;
return 0;
}
ivl_assert(*this, mwid == swid);
ivl_assert(*this, lwid == swid);
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
// signal itself.
if (rel_base == (long)(wid-1) && wid == net->vector_width()) {
delete base;
net->cast_signed(false);
return net;
}
// Otherwise, make a part select that covers the right
// range.
ex = new NetEConst(verinum(rel_base));
if (warn_ob_select) {
if (rel_base < 0) {
cerr << get_fileline() << ": warning: "
<< net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << lsv << "-:" << wid
<< "] is selecting before vector." << endl;
}
if (rel_base + wid > net->vector_width()) {
cerr << get_fileline() << ": warning: "
<< net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << lsv << "-:" << wid
<< "] is selecting after vector." << endl;
}
}
} else {
// Return 'bx for an undefined base.
ex = new NetEConst(verinum(verinum::Vx, wid, true));
ex->set_line(*this);
delete base;
if (warn_ob_select) {
cerr << get_fileline() << ": warning: " << net->name();
if (net->word_index()) cerr << "[]";
cerr << "['bx-:" << wid
<< "] is always outside vector." << endl;
}
return ex;
}
NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this);
delete base;
return ss;
}
ivl_assert(*this, prefix_indices.size()+1 == net->sig()->packed_dims().size());
// Convert the non-constant part select index expression into
// an expression that returns a canonical base.
base = normalize_variable_part_base(prefix_indices, base, net->sig(), wid, false);
NetESelect*ss = new NetESelect(net, base, wid, IVL_SEL_IDX_DOWN);
NetESelect*ss = new NetESelect(net, base, wid, up ? IVL_SEL_IDX_UP : IVL_SEL_IDX_DOWN);
ss->set_line(*this);
if (debug_elaborate) {
@ -6520,12 +6361,12 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
expr_wid);
if (use_sel == index_component_t::SEL_IDX_UP)
return elaborate_expr_net_idx_up_(des, scope, node, found_in,
need_const);
return elaborate_expr_net_idx_up_do_(des, scope, node, found_in,
true, need_const);
if (use_sel == index_component_t::SEL_IDX_DO)
return elaborate_expr_net_idx_do_(des, scope, node, found_in,
need_const);
return elaborate_expr_net_idx_up_do_(des, scope, node, found_in,
false, need_const);
if (use_sel == index_component_t::SEL_BIT)
return elaborate_expr_net_bit_(des, scope, node, found_in,