Fix some bugs with packed array dimensions.
The netparray_t::slice_dimensions bug was the most insidious and caused all manner of confusion. Also fix some other packed array and unpacked array (and mixed) indexing calculations.
This commit is contained in:
parent
df4889ba3d
commit
40b36337e2
50
elab_expr.cc
50
elab_expr.cc
|
|
@ -2832,6 +2832,9 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||||
const index_component_t&index_tail = name_tail.index.back();
|
const index_component_t&index_tail = name_tail.index.back();
|
||||||
ivl_assert(*this, index_tail.msb);
|
ivl_assert(*this, index_tail.msb);
|
||||||
}
|
}
|
||||||
|
// If we have a net in hand, then we can predict what
|
||||||
|
// the slice width will be. If not, then just guess.
|
||||||
|
if (net == 0)
|
||||||
use_width = 1;
|
use_width = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -2864,15 +2867,35 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||||
|
|
||||||
// The width of a signal expression is the width of the signal.
|
// The width of a signal expression is the width of the signal.
|
||||||
if (net != 0) {
|
if (net != 0) {
|
||||||
|
size_t use_depth = name_tail.index.size();
|
||||||
|
// Account for unpacked dimensions by assuming that the
|
||||||
|
// unpacked dimensions are consumed first, so subtract
|
||||||
|
// the unpacked dimensions from the dimension depth
|
||||||
|
// useable for making the slice.
|
||||||
|
if (use_depth >= net->unpacked_dimensions()) {
|
||||||
|
use_depth -= net->unpacked_dimensions();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// In this case, we have a slice of an unpacked
|
||||||
|
// array. This likely handled as an array instead
|
||||||
|
// of a slice. Hmm...
|
||||||
|
use_depth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
expr_type_ = net->data_type();
|
expr_type_ = net->data_type();
|
||||||
expr_width_ = net->vector_width();
|
expr_width_ = net->slice_width(use_depth);
|
||||||
min_width_ = expr_width_;
|
min_width_ = expr_width_;
|
||||||
signed_flag_ = net->get_signed();
|
signed_flag_ = net->get_signed();
|
||||||
if (debug_elaborate) {
|
if (debug_elaborate) {
|
||||||
cerr << get_fileline() << ": PEIdent::test_width: "
|
cerr << get_fileline() << ": PEIdent::test_width: "
|
||||||
<< net->name() << " is a net, "
|
<< net->name() << " is a net, "
|
||||||
<< "type=" << expr_type_
|
<< "type=" << expr_type_
|
||||||
<< ", width=" << expr_width_ << endl;
|
<< ", width=" << expr_width_
|
||||||
|
<< ", signed_=" << (signed_flag_?"true":"false")
|
||||||
|
<< ", use_depth=" << use_depth
|
||||||
|
<< ", packed_dimensions=" << net->packed_dimensions()
|
||||||
|
<< ", unpacked_dimensions=" << net->unpacked_dimensions()
|
||||||
|
<< endl;
|
||||||
}
|
}
|
||||||
return expr_width_;
|
return expr_width_;
|
||||||
}
|
}
|
||||||
|
|
@ -3228,6 +3251,13 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||||
|
|
||||||
if (!tmp) return 0;
|
if (!tmp) return 0;
|
||||||
|
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": PEIdent::elaborate_expr: "
|
||||||
|
<< "Expression as net. expr_wid=" << expr_wid
|
||||||
|
<< ", tmp->expr_width()=" << tmp->expr_width()
|
||||||
|
<< ", tmp=" << *tmp << endl;
|
||||||
|
}
|
||||||
|
|
||||||
tmp = pad_to_width(tmp, expr_wid, *this);
|
tmp = pad_to_width(tmp, expr_wid, *this);
|
||||||
tmp->cast_signed(signed_flag_);
|
tmp->cast_signed(signed_flag_);
|
||||||
|
|
||||||
|
|
@ -4445,6 +4475,15 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||||
// making a mux part in the netlist.
|
// making a mux part in the netlist.
|
||||||
if (NetEConst*msc = dynamic_cast<NetEConst*> (mux)) {
|
if (NetEConst*msc = dynamic_cast<NetEConst*> (mux)) {
|
||||||
|
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": PEIdent::elaborate_expr_net_bit_: "
|
||||||
|
<< "mux is constant=" << *msc
|
||||||
|
<< ", packed_dims()=" << net->sig()->packed_dims()
|
||||||
|
<< ", packed_dims().size()=" << net->sig()->packed_dims().size()
|
||||||
|
<< ", prefix_indices.size()=" << prefix_indices.size()
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
// Special case: The bit select expression is constant
|
// Special case: The bit select expression is constant
|
||||||
// x/z. The result of the expression is 1'bx.
|
// x/z. The result of the expression is 1'bx.
|
||||||
if (! msc->value().is_defined()) {
|
if (! msc->value().is_defined()) {
|
||||||
|
|
@ -4462,6 +4501,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Should I be using slice_width() here?
|
||||||
NetEConst*tmp = make_const_x(1);
|
NetEConst*tmp = make_const_x(1);
|
||||||
tmp->set_line(*this);
|
tmp->set_line(*this);
|
||||||
delete mux;
|
delete mux;
|
||||||
|
|
@ -4553,6 +4593,12 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||||
if (net->vector_width() == 1)
|
if (net->vector_width() == 1)
|
||||||
return net;
|
return net;
|
||||||
|
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": PEIdent::elaborate_expr_net_bit_: "
|
||||||
|
<< "Make bit select idx=" << idx
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
// Make an expression out of the index
|
// Make an expression out of the index
|
||||||
NetEConst*idx_c = new NetEConst(verinum(idx));
|
NetEConst*idx_c = new NetEConst(verinum(idx));
|
||||||
idx_c->set_line(*net);
|
idx_c->set_line(*net);
|
||||||
|
|
|
||||||
17
elab_net.cc
17
elab_net.cc
|
|
@ -708,6 +708,16 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!path_tail.index.empty()) {
|
} else if (!path_tail.index.empty()) {
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: "
|
||||||
|
<< "path_tail.index.size()=" << path_tail.index.size()
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are index expressions on the name, so this is a
|
||||||
|
// bit/slice select of the name. Calculate a canonical
|
||||||
|
// part select.
|
||||||
|
|
||||||
if (sig->get_scalar()) {
|
if (sig->get_scalar()) {
|
||||||
cerr << get_fileline() << ": error: "
|
cerr << get_fileline() << ": error: "
|
||||||
<< "can not select part of ";
|
<< "can not select part of ";
|
||||||
|
|
@ -739,6 +749,13 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||||
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_and_set_part_driver(midx,lidx, widx_flag? widx : 0)) {
|
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_and_set_part_driver(midx,lidx, widx_flag? widx : 0)) {
|
||||||
cerr << get_fileline() << ": error: Unresolved net/uwire "
|
cerr << get_fileline() << ": error: Unresolved net/uwire "
|
||||||
<< sig->name() << " cannot have multiple drivers." << endl;
|
<< sig->name() << " cannot have multiple drivers." << endl;
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": : Overlap in "
|
||||||
|
<< "[" << midx << ":" << lidx << "] (canonical)"
|
||||||
|
<< ", widx=" << (widx_flag? widx : 0)
|
||||||
|
<< ", vector width=" << sig->vector_width()
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -762,6 +762,9 @@ const netclass_t* NetNet::class_type(void) const
|
||||||
* In this case, slice_width(2) == 1 (slice_width(N) where N is the
|
* In this case, slice_width(2) == 1 (slice_width(N) where N is the
|
||||||
* number of dimensions will always be 1.) and represents
|
* number of dimensions will always be 1.) and represents
|
||||||
* $bits(foo[a][b]). Then, slice_width(1)==4 ($bits(foo[a]) and slice_width(0)==24.
|
* $bits(foo[a][b]). Then, slice_width(1)==4 ($bits(foo[a]) and slice_width(0)==24.
|
||||||
|
*
|
||||||
|
* NOTE: The caller should already have accounted for unpacked
|
||||||
|
* dimensions. The "depth" is only for the packed dimensions.
|
||||||
*/
|
*/
|
||||||
unsigned long NetNet::slice_width(size_t depth) const
|
unsigned long NetNet::slice_width(size_t depth) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ vector<netrange_t> netparray_t::slice_dimensions() const
|
||||||
vector<netrange_t> res (packed_dims_.size() + elem_dims.size());
|
vector<netrange_t> res (packed_dims_.size() + elem_dims.size());
|
||||||
|
|
||||||
for (size_t idx = 0 ; idx < packed_dims_.size() ; idx += 1)
|
for (size_t idx = 0 ; idx < packed_dims_.size() ; idx += 1)
|
||||||
res[idx] = packed_dims_[0];
|
res[idx] = packed_dims_[idx];
|
||||||
for (size_t idx = 0 ; idx < elem_dims.size() ; idx += 1)
|
for (size_t idx = 0 ; idx < elem_dims.size() ; idx += 1)
|
||||||
res[idx+packed_dims_.size()] = elem_dims[idx];
|
res[idx+packed_dims_.size()] = elem_dims[idx];
|
||||||
|
|
||||||
|
|
|
||||||
24
nettypes.cc
24
nettypes.cc
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# include "nettypes.h"
|
# include "nettypes.h"
|
||||||
|
# include <iostream>
|
||||||
# include <cassert>
|
# include <cassert>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
@ -101,6 +102,12 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
|
||||||
{
|
{
|
||||||
assert(prefix.size() < dims.size());
|
assert(prefix.size() < dims.size());
|
||||||
|
|
||||||
|
// Figure out the width of the slice, given the number of
|
||||||
|
// prefix numbers there are. We don't need to look at the
|
||||||
|
// actual values yet, but we do need to know how many there
|
||||||
|
// are compared to the actual dimensions of the target. So do
|
||||||
|
// this by multiplying the widths of the dims that are NOT
|
||||||
|
// accounted for by the prefix or sb indices.
|
||||||
size_t acc_wid = 1;
|
size_t acc_wid = 1;
|
||||||
vector<netrange_t>::const_iterator pcur = dims.end();
|
vector<netrange_t>::const_iterator pcur = dims.end();
|
||||||
for (size_t idx = prefix.size()+1 ; idx < dims.size() ; idx += 1) {
|
for (size_t idx = prefix.size()+1 ; idx < dims.size() ; idx += 1) {
|
||||||
|
|
@ -108,8 +115,12 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
|
||||||
acc_wid *= pcur->width();
|
acc_wid *= pcur->width();
|
||||||
}
|
}
|
||||||
|
|
||||||
lwid = acc_wid;
|
lwid = acc_wid; // lwid is now the final slice width.
|
||||||
|
|
||||||
|
// pcur is pointing to the dimension AFTER the dimension that
|
||||||
|
// we have an index for, so step back one, then this will be
|
||||||
|
// used with the sb index. Start accumulating in the acc_off
|
||||||
|
// the offset into the n-dimensional vector.
|
||||||
-- pcur;
|
-- pcur;
|
||||||
if (sb < pcur->get_msb() && sb < pcur->get_lsb())
|
if (sb < pcur->get_msb() && sb < pcur->get_lsb())
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -122,16 +133,18 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
|
||||||
else
|
else
|
||||||
acc_off += (pcur->get_lsb() - sb) * acc_wid;
|
acc_off += (pcur->get_lsb() - sb) * acc_wid;
|
||||||
|
|
||||||
|
// If there are no more prefix items, we are done.
|
||||||
if (prefix.empty()) {
|
if (prefix.empty()) {
|
||||||
loff = acc_off;
|
loff = acc_off;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
lwid *= pcur->width();
|
// Now similarly go through the prefix numbers, working
|
||||||
|
// through the dimensions until we run out. Accumulate a
|
||||||
|
// growing slice width (acc_wid) that is used to caculate the
|
||||||
|
// growing offset (acc_off).
|
||||||
list<long>::const_iterator icur = prefix.end();
|
list<long>::const_iterator icur = prefix.end();
|
||||||
do {
|
do {
|
||||||
-- pcur;
|
|
||||||
-- icur;
|
-- icur;
|
||||||
acc_wid *= pcur->width();
|
acc_wid *= pcur->width();
|
||||||
if (pcur->get_msb() >= pcur->get_lsb())
|
if (pcur->get_msb() >= pcur->get_lsb())
|
||||||
|
|
@ -139,8 +152,11 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
|
||||||
else
|
else
|
||||||
acc_off += (pcur->get_lsb() - *icur) * acc_wid;
|
acc_off += (pcur->get_lsb() - *icur) * acc_wid;
|
||||||
|
|
||||||
|
-- pcur;
|
||||||
|
|
||||||
} while (icur != prefix.begin());
|
} while (icur != prefix.begin());
|
||||||
|
|
||||||
|
// Got our final offset.
|
||||||
loff = acc_off;
|
loff = acc_off;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue