Support assignment of string literals to byte arrays

SystemVerilog defines a special case that allows to assign string literals
to byte arrays. Each character of the string is copied to 1 element of the
byte array.

The size of string literal and the byte array does not have to match. If
the string literal is longer it is truncated. If it is shorter it will be
padded with null-bytes.

The assignment is done left aligned, the first character ends up in the
left most entry of the array. This means the order will differ whether the
array is declared with ascending or descending element order.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2023-06-19 11:36:59 -07:00
parent 8519a30354
commit 272cf91eae
3 changed files with 88 additions and 7 deletions

View File

@ -690,12 +690,16 @@ class PEString : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
width_mode_t&mode) override;
virtual NetEConst*elaborate_expr(Design*des, NetScope*scope,
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
ivl_type_t type, unsigned flags) const override;
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid, unsigned) const override;
NetExpr *elaborate_expr_uarray_(Design *des, NetScope *scope,
const netuarray_t *uarray_type,
const std::vector<netrange_t> &dims,
unsigned int cur_dim) const;
private:
char*text_;
};

View File

@ -344,6 +344,9 @@ NetExpr* PEAssignPattern::elaborate_expr_uarray_(Design *des, NetScope *scope,
if (const auto ap = dynamic_cast<PEAssignPattern*>(parms_[idx])) {
expr = ap->elaborate_expr_uarray_(des, scope, uarray_type,
dims, cur_dim, need_const);
} else if (auto s = dynamic_cast<PEString*>(parms_[idx])) {
expr = s->elaborate_expr_uarray_(des, scope, uarray_type,
dims, cur_dim);
} else if (dynamic_cast<PEConcat*>(parms_[idx])) {
cerr << get_fileline() << ": sorry: "
<< "Array concatenation is not yet supported."
@ -6986,13 +6989,86 @@ unsigned PEString::test_width(Design*, NetScope*, width_mode_t&)
return expr_width_;
}
NetEConst* PEString::elaborate_expr(Design*, NetScope*, ivl_type_t, unsigned) const
NetExpr* PEString::elaborate_expr_uarray_(Design *des, NetScope *,
const netuarray_t *uarray_type,
const std::vector<netrange_t> &dims,
unsigned int cur_dim) const
{
NetECString*tmp = new NetECString(value());
tmp->cast_signed(signed_flag_);
tmp->set_line(*this);
// This is a special case. The LRM allows string literals to be
// assigned to unpacked arrays of bytes.
const auto element_type = uarray_type->element_type();
return tmp;
if (dims.size() - 1 != cur_dim || !element_type->packed() ||
element_type->base_type() != IVL_VT_BOOL ||
element_type->packed_width() != 8 || !element_type->get_signed()) {
cerr << get_fileline() << ": error: "
<< "String literal can not be implicitly cast to the target type."
<< endl;
des->errors++;
return nullptr;
}
// The size doesn't have to match. Elements are copied left aligned, which
// is different from assignments of string literals to packed arrays where
// they are copied right aligned.
vector<NetExpr*> elem_exprs(dims[cur_dim].width());
bool asc = dims[cur_dim].get_msb() < dims[cur_dim].get_lsb();
unsigned int elem_idx = asc ? 0 : elem_exprs.size() - 1;
verinum text_val(text_);
if (text_val.len() > elem_exprs.size() * 8) {
cerr << get_fileline() << ": warning: "
<< "Target array smaller than assigned value. "
<< "Value will be truncated." << endl;
}
for (unsigned int i = 0; i < min((size_t)text_val.len() / 8, elem_exprs.size()); i++) {
verinum val(text_val >> (text_val.len() - 8 - i * 8), 8);
val.has_sign(true);
elem_exprs[elem_idx] = new NetEConst(element_type, val);
if (asc)
elem_idx++;
else
elem_idx--;
}
// Add padding if necessary
for (unsigned int i = text_val.len() / 8; i < elem_exprs.size(); i++) {
verinum val(verinum::V0, 8);
val.has_sign(true);
elem_exprs[elem_idx] = new NetEConst(element_type, val);
if (asc)
elem_idx++;
else
elem_idx--;
}
return new NetEArrayPattern(uarray_type, elem_exprs);
}
NetExpr* PEString::elaborate_expr(Design *des, NetScope *scope, ivl_type_t type, unsigned) const
{
NetExpr *expr;
auto uarray_type = dynamic_cast<const netuarray_t*>(type);
if (uarray_type) {
expr = elaborate_expr_uarray_(des, scope, uarray_type,
uarray_type->static_dimensions(), 0);
} else {
expr = new NetECString(value());
expr->cast_signed(signed_flag_);
}
if (expr)
expr->set_line(*this);
return expr;
}
/*

View File

@ -266,7 +266,8 @@ NetNet *elaborate_unpacked_array(Design *des, NetScope *scope, const LineInfo &l
<< endl;
des->errors++;
return nullptr;
} else if (dynamic_cast<PEAssignPattern*> (expr)) {
} else if (dynamic_cast<PEAssignPattern*> (expr) ||
dynamic_cast<PEString*> (expr)) {
auto net_expr = elaborate_rval_expr(des, scope, lval->array_type(), expr);
if (! net_expr) return nullptr;
expr_net = net_expr->synthesize(des, scope, net_expr);