Support $bits() for arrays and array slices
`$bits()` for array types is supposed to return the full size of the array in bits. This currently works for data types that are passed to `$bits()`, but not for array typed identifiers. E.g. ``` typedef int T[1:0]; T x; $display($bits(T)); // -> 64 $display(x); // -> 32 ``` Since the `$bits()` implementation uses the expr_width of an expression include the size of the unpacked dimensions in that for array identifiers and array slices. Strictly speaking an array identifier does not have an expression width, but this would be its expression with if it were for example bitstream cast to a vector. Special care needs to be take to not trying to pad array identifier expressions. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
a3f1aded7c
commit
7908e15093
34
elab_expr.cc
34
elab_expr.cc
|
|
@ -4289,10 +4289,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
||||
if (!name_tail.index.empty()) {
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
// Skip full array word net selects.
|
||||
if (!sr.net || (name_tail.index.size() > sr.net->unpacked_dimensions())) {
|
||||
use_sel = index_tail.sel;
|
||||
}
|
||||
use_sel = index_tail.sel;
|
||||
}
|
||||
|
||||
unsigned use_width = UINT_MAX;
|
||||
|
|
@ -4380,13 +4377,12 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
}
|
||||
}
|
||||
|
||||
if (use_width != UINT_MAX) {
|
||||
size_t use_depth = name_tail.index.size();
|
||||
if (use_width != UINT_MAX && (!sr.net || use_depth > sr.net->unpacked_dimensions())) {
|
||||
// We have a bit/part select. Account for any remaining dimensions
|
||||
// beyond the indexed dimension.
|
||||
size_t use_depth = name_tail.index.size();
|
||||
if (sr.net) {
|
||||
if (use_depth >= sr.net->unpacked_dimensions())
|
||||
use_depth -= sr.net->unpacked_dimensions();
|
||||
use_depth -= sr.net->unpacked_dimensions();
|
||||
use_width *= sr.net->slice_width(use_depth);
|
||||
}
|
||||
|
||||
|
|
@ -4426,23 +4422,29 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
}
|
||||
}
|
||||
|
||||
size_t use_depth = name_tail.index.size();
|
||||
// Unindexed indentifier
|
||||
if (use_width == UINT_MAX)
|
||||
use_width = 1;
|
||||
// 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 >= sr.net->unpacked_dimensions()) {
|
||||
use_depth -= sr.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...
|
||||
// In this case, we have an unpacked array or a slice of an
|
||||
// unpacked array. These expressions strictly speaking do
|
||||
// not have a width. But we use the value calculated here
|
||||
// for things $bits(), so return the full number of bits of
|
||||
// the expression.
|
||||
const auto &dims = sr.net->unpacked_dims();
|
||||
for (size_t idx = use_depth; idx < dims.size(); idx++)
|
||||
use_width *= dims[idx].width();
|
||||
use_depth = 0;
|
||||
}
|
||||
|
||||
expr_type_ = sr.net->data_type();
|
||||
expr_width_ = sr.net->slice_width(use_depth);
|
||||
expr_width_ = sr.net->slice_width(use_depth) * use_width;
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = sr.net->get_signed();
|
||||
if (debug_elaborate) {
|
||||
|
|
@ -4648,6 +4650,10 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
if (!result || !type_is_vectorable(expr_type_))
|
||||
return result;
|
||||
|
||||
auto net_type = result->net_type();
|
||||
if (net_type && !net_type->packed())
|
||||
return result;
|
||||
|
||||
return pad_to_width(result, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2432,10 +2432,10 @@ NetESignal::NetESignal(NetNet*n, NetExpr*w)
|
|||
net_->incr_eref();
|
||||
set_line(*n);
|
||||
|
||||
// If it is an array we don't have a type for it yet. But for array
|
||||
// elements the NetNet returns the element type.
|
||||
if (word_)
|
||||
set_net_type(net_->net_type());
|
||||
else
|
||||
set_net_type(net_->array_type());
|
||||
}
|
||||
|
||||
NetESignal::~NetESignal()
|
||||
|
|
|
|||
Loading…
Reference in New Issue