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.
This commit is contained in:
parent
ad862020bb
commit
0fada92389
28
elab_expr.cc
28
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<const netstruct_t*>(member->net_type)) {
|
||||
if (const netstruct_t*tmp_struct = dynamic_cast<const netstruct_t*>(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<const netenum_t*> (member->net_type)) {
|
||||
} else if (const netenum_t*tmp_enum = dynamic_cast<const netenum_t*> (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<const netvector_t*>(member->net_type)) {
|
||||
} else if (const netvector_t*mem_vec = dynamic_cast<const netvector_t*>(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<const netparray_t*>(member->net_type)) {
|
||||
} else if (const netparray_t*array = dynamic_cast<const netparray_t*>(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;
|
||||
}
|
||||
|
|
|
|||
32
net_expr.cc
32
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<NetESignal*>(expr_);
|
||||
ivl_assert(*this, sig);
|
||||
const netarray_t*array_type = dynamic_cast<const netarray_t*> (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<const netenum_t*> (use_type_);
|
||||
}
|
||||
|
||||
bool NetESelect::has_width() const
|
||||
|
|
|
|||
13
netlist.h
13
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_;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue