diff --git a/elab_sig.cc b/elab_sig.cc index 0b85f08a7..7f2c8780a 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -38,7 +38,6 @@ # include "netmisc.h" # include "netclass.h" # include "netenum.h" -# include "netstruct.h" # include "netvector.h" # include "netdarray.h" # include "netparray.h" @@ -873,47 +872,6 @@ static netclass_t* locate_class_type(Design*, NetScope*scope, return use_class; } -netstruct_t* struct_type_t::elaborate_type(Design*des, NetScope*scope) const -{ - netstruct_t*res = new netstruct_t; - - res->packed(packed_flag); - - if (union_flag) - res->union_flag(true); - - for (list::iterator cur = members->begin() - ; cur != members->end() ; ++ cur) { - - vectorpacked_dimensions; - - struct_member_t*curp = *cur; - vector_type_t*vecp = dynamic_cast (curp->type.get()); - if (vecp && vecp->pdims.get() && ! vecp->pdims->empty()) { - bool bad_range; - bad_range = evaluate_ranges(des, scope, packed_dimensions, *vecp->pdims); - ivl_assert(*curp, !bad_range); - } else { - packed_dimensions.push_back(netrange_t(0,0)); - } - - netvector_t*mem_vec = new netvector_t(packed_dimensions, - curp->type->figure_packed_base_type()); - - for (list::iterator name = curp->names->begin() - ; name != curp->names->end() ; ++ name) { - decl_assignment_t*namep = *name; - - netstruct_t::member_t memb; - memb.name = namep->name; - memb.net_type = mem_vec; - res->append_member(memb); - } - } - - return res; -} - static ivl_type_s*elaborate_type(Design*des, NetScope*scope, data_type_t*pform_type) { diff --git a/elab_type.cc b/elab_type.cc index 60e04e8ca..f9c17bba5 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -22,6 +22,7 @@ # include "netclass.h" # include "netdarray.h" # include "netscalar.h" +# include "netstruct.h" # include "netvector.h" # include "netmisc.h" # include @@ -130,6 +131,39 @@ ivl_type_s* string_type_t::elaborate_type(Design*, NetScope*) const return &netstring_t::type_string; } +netstruct_t* struct_type_t::elaborate_type(Design*des, NetScope*scope) const +{ + netstruct_t*res = new netstruct_t; + + res->packed(packed_flag); + + if (union_flag) + res->union_flag(true); + + for (list::iterator cur = members->begin() + ; cur != members->end() ; ++ cur) { + + // Elaborate the type of the member. + struct_member_t*curp = *cur; + ivl_type_t mem_vec = curp->type->elaborate_type(des, scope); + + // There may be several names that are the same type: + // name1, name2, ...; + // Process all the member, and give them a type. + for (list::iterator name = curp->names->begin() + ; name != curp->names->end() ; ++ name) { + decl_assignment_t*namep = *name; + + netstruct_t::member_t memb; + memb.name = namep->name; + memb.net_type = mem_vec; + res->append_member(des, memb); + } + } + + return res; +} + ivl_type_s* uarray_type_t::elaborate_type(Design*des, NetScope*scope) const { diff --git a/netstruct.cc b/netstruct.cc index 982fdb4fb..a2182e671 100644 --- a/netstruct.cc +++ b/netstruct.cc @@ -17,10 +17,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +# include "netlist.h" # include "netstruct.h" # include "netvector.h" # include +# include "ivl_assert.h" + using namespace std; netstruct_t::netstruct_t() @@ -34,17 +37,43 @@ netstruct_t::~netstruct_t() void netstruct_t::union_flag(bool flag) { + // This MUST be called before any members are pushed into the + // definition. This is because the append relies on this flag + // being accurate. + ivl_assert(*this, members_.empty()); union_ = flag; } void netstruct_t::packed(bool flag) { + ivl_assert(*this, members_.empty()); packed_ = flag; } -void netstruct_t::append_member(const netstruct_t::member_t&val) +void netstruct_t::append_member(Design*des, const netstruct_t::member_t&val) { members_.push_back(val); + if (packed_) { + if (! members_.back().net_type->packed()) { + cerr << get_fileline() << ": error: " + << "Member " << members_.back().name + << " of packed struct/union" + << " must be packed." << endl; + des->errors += 1; + } + } + if (union_ && packed_ && members_.size() > 1) { + unsigned long expect_wid = members_.front().net_type->packed_width(); + unsigned long got_wid = members_.back().net_type->packed_width(); + if (expect_wid != got_wid) { + cerr << get_fileline() << ": error: " + << "Member " << val.name + << " of packed union" + << " is " << got_wid + << " bits, expecting " << expect_wid << " bits." << endl; + des->errors += 1; + } + } } const netstruct_t::member_t* netstruct_t::packed_member(perm_string name, unsigned long&off) const @@ -55,7 +84,11 @@ const netstruct_t::member_t* netstruct_t::packed_member(perm_string name, unsign off = count_off; return &members_[idx-1]; } - count_off += members_[idx-1].net_type->packed_width(); + // If this is not a union, then the members are lined up + // from LSB to MSB. If this is a union, then all + // members are at offset 0. + if (!union_) + count_off += members_[idx-1].net_type->packed_width(); } return 0; @@ -66,6 +99,13 @@ long netstruct_t::packed_width(void) const if (! packed_) return -1; + // If this is a packed union, then all the members are the + // same width, so it is sufficient to return the width of any + // single member. + if (union_) + return members_.front().net_type->packed_width(); + + // The width of a packed struct is the sum of member widths. long res = 0; for (size_t idx = 0 ; idx < members_.size() ; idx += 1) res += members_[idx].net_type->packed_width(); diff --git a/netstruct.h b/netstruct.h index c754abe2d..8c0f4a88e 100644 --- a/netstruct.h +++ b/netstruct.h @@ -24,6 +24,8 @@ # include "ivl_target.h" # include "nettypes.h" +class Design; + class netstruct_t : public LineInfo, public ivl_type_s { public: @@ -49,7 +51,11 @@ class netstruct_t : public LineInfo, public ivl_type_s { void packed(bool flag); bool packed(void) const; - void append_member(const member_t&); + // Append a new member to the struct/union. This must be done + // after the union_flag and packed settings are set. This + // function does error checking, and the "des" argument is + // only present so that it can set error flags. + void append_member(Design*des, const member_t&); // Given the name of a member, return a pointer to the member // description, and set the off value to be the offset into