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 <lars@metafoo.de>
This commit is contained in:
parent
f9909562fd
commit
d0613f24b8
17
elab_lval.cc
17
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<const netvector_t*>(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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue