diff --git a/elab_expr.cc b/elab_expr.cc index 02cf08fb8..481430024 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -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 (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); diff --git a/elab_net.cc b/elab_net.cc index 2495b9d6c..cbaf15202 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -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; } diff --git a/netlist.cc b/netlist.cc index e43c52046..4d184dc51 100644 --- a/netlist.cc +++ b/netlist.cc @@ -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 { diff --git a/netparray.cc b/netparray.cc index d8779a92d..326b549fc 100644 --- a/netparray.cc +++ b/netparray.cc @@ -49,7 +49,7 @@ vector netparray_t::slice_dimensions() const vector 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]; diff --git a/nettypes.cc b/nettypes.cc index 1a36b177a..4a01d4d8a 100644 --- a/nettypes.cc +++ b/nettypes.cc @@ -18,6 +18,7 @@ */ # include "nettypes.h" +# include # include using namespace std; @@ -101,6 +102,12 @@ bool prefix_to_slice(const std::vector&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::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&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&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::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&dims, else acc_off += (pcur->get_lsb() - *icur) * acc_wid; + -- pcur; + } while (icur != prefix.begin()); + // Got our final offset. loff = acc_off; return true;