From 0fada92389dc429f8bbc9f0d7ebc385f02cf8fd6 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 20 Nov 2020 16:50:11 +0000 Subject: [PATCH] Fix expression type for packed struct member access (GitHub issue #386) A NetESelect is used for accessing packed struct members and also for accessing dynamic array elements. In these cases the expr_type() and enumeration() methods should reflect the member/element type. --- elab_expr.cc | 28 ++++++++++++++++------------ net_expr.cc | 32 +++++++++++++++++--------------- netlist.h | 13 +++++++++++-- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 4d9694885..e28b6ede8 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1958,6 +1958,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li, unsigned long use_width = struct_type->packed_width(); pform_name_t completed_path; + ivl_type_t member_type = 0; do { const name_component_t member_comp = member_path.front(); const perm_string&member_name = member_comp.name; @@ -1985,28 +1986,29 @@ static NetExpr* check_for_struct_members(const LineInfo*li, des->errors += 1; return 0; } + member_type = member->net_type; if (debug_elaborate) { cerr << li->get_fileline() << ": check_for_struct_members: " - << "Member type: " << *(member->net_type) - << " (" << typeid(*(member->net_type)).name() << ")" + << "Member type: " << *member_type + << " (" << typeid(*member_type).name() << ")" << endl; } off += tmp_off; - ivl_assert(*li, use_width >= (unsigned long)member->net_type->packed_width()); - use_width = member->net_type->packed_width(); + ivl_assert(*li, use_width >= (unsigned long)member_type->packed_width()); + use_width = member_type->packed_width(); // At this point, off and use_width are the part select // expressed by the member_comp, which is a member of the // struct. We can further refine the part select with any // indices that might be present. - if (const netstruct_t*tmp_struct = dynamic_cast(member->net_type)) { + if (const netstruct_t*tmp_struct = dynamic_cast(member_type)) { // If the member is itself a struct, then get // ready to go on to the next iteration. struct_type = tmp_struct; - } else if (const netenum_t*tmp_enum = dynamic_cast (member->net_type)) { + } else if (const netenum_t*tmp_enum = dynamic_cast (member_type)) { // If the element is an enum, then we don't have // anything special to do. @@ -2017,7 +2019,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li, } struct_type = 0; - } else if (const netvector_t*mem_vec = dynamic_cast(member->net_type)) { + } else if (const netvector_t*mem_vec = dynamic_cast(member_type)) { if (debug_elaborate) { cerr << li->get_fileline() << ": check_for_struct_members: " @@ -2104,7 +2106,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li, // there is no next struct type. struct_type = 0; - } else if (const netparray_t*array = dynamic_cast(member->net_type)) { + } else if (const netparray_t*array = dynamic_cast(member_type)) { // If the member is a parray, then the elements // are themselves packed object, including @@ -2178,7 +2180,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li, } else { // Unknown type? cerr << li->get_fileline() << ": internal error: " - << "Unexpected member type? " << *(member->net_type) + << "Unexpected member type? " << *member_type << endl; des->errors += 1; struct_type = 0; @@ -2224,7 +2226,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li, NetESignal*sig = new NetESignal(net); NetExpr *base = packed_base? packed_base : make_const_val(off); - NetESelect*sel = new NetESelect(sig, base, use_width); + NetESelect*sel = new NetESelect(sig, base, use_width, member_type); if (debug_elaborate) { cerr << li->get_fileline() << ": check_for_struct_member: " @@ -5395,7 +5397,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, cerr << get_fileline() << ": debug: " << "Bit select of a dynamic array becomes NetESelect." << endl; } - NetESelect*res = new NetESelect(net, mux, darray->element_width()); + NetESelect*res = new NetESelect(net, mux, darray->element_width(), darray->element_type()); res->set_line(*net); return res; } @@ -5597,13 +5599,15 @@ NetExpr* PEIdent::elaborate_expr_net_bit_last_(Design*, NetScope*, } unsigned use_width = 1; + ivl_type_t use_type = 0; if (const netdarray_t*darray = net->sig()->darray_type()) { use_width = darray->element_width(); + use_type = darray->element_type(); } NetELast*mux = new NetELast(net->sig()); mux->set_line(*this); - NetESelect*ss = new NetESelect(net, mux, use_width); + NetESelect*ss = new NetESelect(net, mux, use_width, use_type); ss->set_line(*this); return ss; } diff --git a/net_expr.cc b/net_expr.cc index ecbcd96e3..804fae96d 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2020 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -403,7 +403,14 @@ ivl_variable_type_t NetEProperty::expr_type() const NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid, ivl_select_type_t sel_type) -: expr_(exp), base_(base), sel_type_(sel_type) +: expr_(exp), base_(base), use_type_(0), sel_type_(sel_type) +{ + expr_width(wid); +} + +NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid, + ivl_type_t use_type) +: expr_(exp), base_(base), use_type_(use_type), sel_type_(IVL_SEL_OTHER) { expr_width(wid); } @@ -431,6 +438,9 @@ ivl_select_type_t NetESelect::select_type() const ivl_variable_type_t NetESelect::expr_type() const { + if (use_type_) + return use_type_->base_type(); + ivl_variable_type_t type = expr_->expr_type(); // Special case: If the sub-expression is an IVL_VT_STRING, @@ -439,20 +449,12 @@ ivl_variable_type_t NetESelect::expr_type() const if (type == IVL_VT_STRING && expr_width()==8) return IVL_VT_BOOL; - if (type != IVL_VT_DARRAY) - return type; + return type; +} - ivl_assert(*this, type == IVL_VT_DARRAY); - - // Special case: If the expression is a DARRAY, then the - // sub-expression must be a NetESignal and the type of the - // NetESelect expression is the element type of the arrayed signal. - NetESignal*sig = dynamic_cast(expr_); - ivl_assert(*this, sig); - const netarray_t*array_type = dynamic_cast (sig->sig()->net_type()); - ivl_assert(*this, array_type); - - return array_type->element_type()->base_type(); +const netenum_t* NetESelect::enumeration() const +{ + return dynamic_cast (use_type_); } bool NetESelect::has_width() const diff --git a/netlist.h b/netlist.h index fec381cdd..202153830 100644 --- a/netlist.h +++ b/netlist.h @@ -4401,21 +4401,29 @@ class NetEConcat : public NetExpr { * If the base expression is null, then this expression node can be * used to express width expansion, signed or unsigned depending on * the has_sign() flag. + * + * An alternative form of this expression node is used for dynamic + * array word selects and for packed struct member selects. In this + * case use_type indicates the type of the selected element/member. */ class NetESelect : public NetExpr { public: NetESelect(NetExpr*exp, NetExpr*base, unsigned wid, ivl_select_type_t sel_type = IVL_SEL_OTHER); + NetESelect(NetExpr*exp, NetExpr*base, unsigned wid, + ivl_type_t use_type); ~NetESelect(); const NetExpr*sub_expr() const; const NetExpr*select() const; ivl_select_type_t select_type() const; - // The type of a NetESelect is the base type of the - // sub-expression. + // The type of a bit/part select is the base type of the + // sub-expression. The type of an array/member select is + // the base type of the element/member. virtual ivl_variable_type_t expr_type() const; + virtual const netenum_t* enumeration() const; virtual NexusSet* nex_input(bool rem_out = true, bool always_sens = false, bool nested_func = false) const; @@ -4431,6 +4439,7 @@ class NetESelect : public NetExpr { private: NetExpr*expr_; NetExpr*base_; + ivl_type_t use_type_; ivl_select_type_t sel_type_; };