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:
Stephen Williams 2014-04-05 20:57:22 -07:00
parent df4889ba3d
commit 40b36337e2
5 changed files with 90 additions and 8 deletions

View File

@ -2832,7 +2832,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb);
}
use_width = 1;
// 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;
break;
default:
ivl_assert(*this, 0);
@ -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.
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_width_ = net->vector_width();
expr_width_ = net->slice_width(use_depth);
min_width_ = expr_width_;
signed_flag_ = net->get_signed();
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::test_width: "
<< net->name() << " is a net, "
<< "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_;
}
@ -3228,6 +3251,13 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
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->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.
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
// x/z. The result of the expression is 1'bx.
if (! msc->value().is_defined()) {
@ -4462,6 +4501,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
<< endl;
}
// FIXME: Should I be using slice_width() here?
NetEConst*tmp = make_const_x(1);
tmp->set_line(*this);
delete mux;
@ -4553,6 +4593,12 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
if (net->vector_width() == 1)
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
NetEConst*idx_c = new NetEConst(verinum(idx));
idx_c->set_line(*net);

View File

@ -708,6 +708,16 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
}
} 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()) {
cerr << get_fileline() << ": error: "
<< "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)) {
cerr << get_fileline() << ": error: Unresolved net/uwire "
<< 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;
return 0;
}

View File

@ -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
* 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.
*
* 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
{

View File

@ -49,7 +49,7 @@ vector<netrange_t> netparray_t::slice_dimensions() const
vector<netrange_t> res (packed_dims_.size() + elem_dims.size());
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)
res[idx+packed_dims_.size()] = elem_dims[idx];

View File

@ -18,6 +18,7 @@
*/
# include "nettypes.h"
# include <iostream>
# include <cassert>
using namespace std;
@ -101,6 +102,12 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
{
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;
vector<netrange_t>::const_iterator pcur = dims.end();
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();
}
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;
if (sb < pcur->get_msb() && sb < pcur->get_lsb())
return false;
@ -122,16 +133,18 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
else
acc_off += (pcur->get_lsb() - sb) * acc_wid;
// If there are no more prefix items, we are done.
if (prefix.empty()) {
loff = acc_off;
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();
do {
-- pcur;
-- icur;
acc_wid *= pcur->width();
if (pcur->get_msb() >= pcur->get_lsb())
@ -139,8 +152,11 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
else
acc_off += (pcur->get_lsb() - *icur) * acc_wid;
-- pcur;
} while (icur != prefix.begin());
// Got our final offset.
loff = acc_off;
return true;