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:
Lars-Peter Clausen 2023-06-25 08:21:19 -07:00
parent a3f1aded7c
commit 7908e15093
2 changed files with 22 additions and 16 deletions

View File

@ -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);
}

View File

@ -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()