From d0613f24b8df3a00eed75ef5586c623d7f67f726 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 15 Jan 2023 17:34:53 -0800 Subject: [PATCH] Allow to attach data type to lvalue part select In most cases the type of an lvalue part select is the base type of the lvalue with the width of the part select. But there are some exceptions. 1) An index into a `string` type is of type `byte`. 2) Packed structs are implemented as packed arrays under the hood. A lvalue struct member is elaborated as a normal part select on a packed array. The type of that select should be the type of the member. For the case 1 there is some special handling for strings that accounts for this. But for case 2 the type information of the member is lost. This works fine for most things but there are a few constructs where the type information is required. * Enum type compatibility check * Assignment pattern behavior depends on the type of the lvalue Allow to attach a specific type to a lvalue part select to allow correct behavior for constructs where the type is required. Signed-off-by: Lars-Peter Clausen --- elab_lval.cc | 17 ++++++++++++----- net_assign.cc | 18 ++++++++++++------ netlist.h | 6 ++++++ 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/elab_lval.cc b/elab_lval.cc index d197fb8eb..332500b23 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -605,10 +605,9 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, cerr << get_fileline() << ": debug: " << "Bit select of string becomes character select." << endl; } - if (mux) - lv->set_part(mux, 8); - else - lv->set_part(new NetEConst(verinum(lsb)), 8); + if (!mux) + mux = new NetEConst(verinum(lsb)); + lv->set_part(mux, &netvector_t::atom2s8); } else if (mux) { ivl_assert(*this, reg->type()!=NetNet::UNRESOLVED_WIRE); @@ -1180,6 +1179,7 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, // increases, and use_width shrinks. unsigned long off = 0; unsigned long use_width = struct_type->packed_width(); + ivl_type_t member_type; pform_name_t completed_path; do { @@ -1251,6 +1251,8 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, return false; } + member_type = member->net_type; + if (const netvector_t*mem_vec = dynamic_cast(member->net_type)) { // If the member type is a netvector_t, then it is a // vector of atom or scaler objects. For example, if the @@ -1320,6 +1322,7 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, off += loff; use_width = lwid * tail_wid; + member_type = nullptr; } // The netvector_t only has atom elements, to @@ -1484,7 +1487,11 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, } if (packed_base == 0) { - lv->set_part(new NetEConst(verinum(off)), use_width); + NetExpr *base = new NetEConst(verinum(off)); + if (member_type) + lv->set_part(base, member_type); + else + lv->set_part(base, use_width); return true; } diff --git a/net_assign.cc b/net_assign.cc index e586e36df..fc8ffdb55 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -126,10 +126,6 @@ unsigned NetAssign_::lwidth() const ivl_variable_type_t NetAssign_::expr_type() const { ivl_type_t ntype = net_type(); - - if (sig_ && sig_->data_type()==IVL_VT_STRING && base_!=0) - return IVL_VT_BOOL; - if (ntype) return ntype->base_type(); @@ -139,10 +135,14 @@ ivl_variable_type_t NetAssign_::expr_type() const ivl_type_t NetAssign_::net_type() const { - // This is a concatenation or a part select, it does not have a type - if (more || base_) + // This is a concatenation, it does not have a type + if (more) return nullptr; + // Selected sub-vector can have its own data type + if (base_) + return part_data_type_; + ivl_type_t ntype; if (nest_) { ntype = nest_->net_type(); @@ -200,6 +200,12 @@ void NetAssign_::set_part(NetExpr*base, unsigned wid, sel_type_ = sel_type; } +void NetAssign_::set_part(NetExpr*base, ivl_type_t data_type) +{ + part_data_type_ = data_type; + set_part(base, part_data_type_->packed_width()); +} + void NetAssign_::set_property(const perm_string&mname, unsigned idx) { member_ = mname; diff --git a/netlist.h b/netlist.h index aeedacf33..14e28832c 100644 --- a/netlist.h +++ b/netlist.h @@ -2836,6 +2836,11 @@ class NetAssign_ { // that the expression calculates a CANONICAL bit address. void set_part(NetExpr* loff, unsigned wid, ivl_select_type_t = IVL_SEL_OTHER); + // Set a part select expression for the l-value vector. Note + // that the expression calculates a CANONICAL bit address. + // The part select has a specific type and the width of the select will + // be that of the type. + void set_part(NetExpr *loff, ivl_type_t data_type); // Set the member or property name if the signal type is a // class. void set_property(const perm_string&name, unsigned int idx); @@ -2905,6 +2910,7 @@ class NetAssign_ { NetExpr*base_; unsigned lwid_; ivl_select_type_t sel_type_; + ivl_type_t part_data_type_ = nullptr; }; class NetAssignBase : public NetProc {