Handle packed unions properly during elaboration.

This also gets r-value use of packed unions correct.
This commit is contained in:
Stephen Williams 2013-11-30 18:20:01 -08:00
parent 49756a8e7a
commit 0d6c15e45a
4 changed files with 83 additions and 45 deletions

View File

@ -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<struct_member_t*>::iterator cur = members->begin()
; cur != members->end() ; ++ cur) {
vector<netrange_t>packed_dimensions;
struct_member_t*curp = *cur;
vector_type_t*vecp = dynamic_cast<vector_type_t*> (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<decl_assignment_t*>::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)
{

View File

@ -22,6 +22,7 @@
# include "netclass.h"
# include "netdarray.h"
# include "netscalar.h"
# include "netstruct.h"
# include "netvector.h"
# include "netmisc.h"
# include <typeinfo>
@ -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<struct_member_t*>::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:
// <data_type> name1, name2, ...;
// Process all the member, and give them a type.
for (list<decl_assignment_t*>::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
{

View File

@ -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 <iostream>
# 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();

View File

@ -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