diff --git a/elab_expr.cc b/elab_expr.cc index b3d3458d5..cd3555c3e 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -29,6 +29,7 @@ # include "netenum.h" # include "discipline.h" # include "netmisc.h" +# include "netstruct.h" # include "util.h" # include "ivl_assert.h" @@ -1422,9 +1423,30 @@ static NetExpr* check_for_struct_members(const LineInfo*li, Design*des, NetScope*scope, NetNet*net, perm_string method_name) { - cerr << li->get_fileline() << ": sorry: structures not supported here." << endl; - des->errors += 1; - return 0; + netstruct_t*type = net->struct_type(); + ivl_assert(*li, type); + + if (! type->packed()) { + cerr << li->get_fileline() << ": sorry: unpacked structures not supported here. " + << "Method=" << method_name << endl; + des->errors += 1; + return 0; + } + + unsigned long off; + const netstruct_t::member_t*mem = type->packed_member(method_name, off); + if (mem == 0) + return 0; + + if (debug_elaborate) { + cerr << li->get_fileline() << ": debug: Found struct member " <name + << " At offset " << off << endl; + } + + NetESignal*sig = new NetESignal(net); + NetEConst*base = make_const_val(off); + NetESelect*sel = new NetESelect(sig, base, mem->width()); + return sel; } NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, diff --git a/elab_sig.cc b/elab_sig.cc index cf435013e..f391a5d9a 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -781,6 +781,51 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const statement_->elaborate_sig(des, scope); } +static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, + struct_type_t*struct_type) +{ + netstruct_t*res = new netstruct_t; + + res->packed(struct_type->packed_flag); + + for (list::iterator cur = struct_type->members->begin() + ; cur != struct_type->members->end() ; ++ cur) { + + struct_member_t*curp = *cur; + long use_msb = 0; + long use_lsb = 0; + if (! curp->range->empty()) { + ivl_assert(*curp, curp->range->size() == 2); + PExpr*msb_pex = curp->range->front(); + PExpr*lsb_pex = curp->range->back(); + + NetExpr*tmp = elab_and_eval(des, scope, msb_pex, -2, true); + ivl_assert(*curp, tmp); + bool rc = eval_as_long(use_msb, tmp); + ivl_assert(*curp, rc); + + tmp = elab_and_eval(des, scope, lsb_pex, -2, true); + ivl_assert(*curp, tmp); + rc = eval_as_long(use_lsb, tmp); + ivl_assert(*curp, rc); + } + + 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.type = curp->type; + memb.msb = use_msb; + memb.lsb = use_lsb; + res->append_member(memb); + } + } + + return res; +} + /* * Elaborate a source wire. The "wire" is the declaration of wires, * registers, ports and memories. The parser has already merged the @@ -1069,37 +1114,53 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } } - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Create signal " << wtype; - if (!get_scalar()) { - cerr << " ["<packed()) + cerr << " " << use_type->packed_width() << " bit packed struct "; + else + cerr << " struct <> "; + cerr << name_; + cerr << " in scope " << scope_path(scope) << endl; } - cerr << " " << name_; - if (array_dimensions > 0) { - cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl; + + sig = new NetNet(scope, name_, wtype, use_type); + + } else { + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Create signal " << wtype; + if (!get_scalar()) { + cerr << " ["< 0) { + cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl; + } + cerr << " in scope " << scope_path(scope) << endl; } - cerr << " in scope " << scope_path(scope) << endl; + + sig = array_dimensions > 0 + ? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0) + : new NetNet(scope, name_, wtype, msb, lsb); } - - NetNet*sig = array_dimensions > 0 - ? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0) - : new NetNet(scope, name_, wtype, msb, lsb); - // If this is an enumeration, then set the enumeration set for // the new signal. This turns it into an enumeration. if (enum_type_) { + ivl_assert(*this, struct_type_ == 0); ivl_assert(*this, ! enum_type_->names->empty()); list::const_iterator sample_name = enum_type_->names->begin(); netenum_t*use_enum = scope->enumeration_for_name(sample_name->name); sig->set_enumeration(use_enum); } - if (struct_type_) { - netstruct_t*use_type = new netstruct_t; - sig->set_struct_type(use_type); - } - if (wtype == NetNet::WIRE) sig->devirtualize_pins(); ivl_variable_type_t use_data_type = data_type_; diff --git a/netlist.cc b/netlist.cc index 67899ba0a..eeaa48d41 100644 --- a/netlist.cc +++ b/netlist.cc @@ -27,6 +27,7 @@ # include "compiler.h" # include "netlist.h" # include "netmisc.h" +# include "netstruct.h" # include "ivl_assert.h" @@ -579,6 +580,51 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, s->add_signal(this); } +static unsigned calculate_count(netstruct_t*type) +{ + long wid = type->packed_width(); + if (wid >= 0) + return wid; + else + return 1; +} + +/* + * When we create a netnet for a packed struct, create a single + * vector with the msb_/lsb_ chosen to name enough bits for the entire + * packed structure. + */ +NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty) +: NetObj(s, n, 1), + type_(t), port_type_(NOT_A_PORT), + data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), + is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(ty), + discipline_(0), msb_(calculate_count(ty)-1), lsb_(0), + dimensions_(0), s0_(0), e0_(0), + eref_count_(0), lref_count_(0) +{ + Link::DIR dir = Link::PASSIVE; + + switch (t) { + case REG: + case IMPLICIT_REG: + dir = Link::OUTPUT; + break; + case SUPPLY0: + dir = Link::OUTPUT; + break; + case SUPPLY1: + dir = Link::OUTPUT; + break; + default: + break; + } + + initialize_dir_(dir); + + s->add_signal(this); +} + NetNet::~NetNet() { if (eref_count_ > 0) { @@ -704,13 +750,6 @@ netstruct_t*NetNet::struct_type(void) const return struct_type_; } -void NetNet::set_struct_type(netstruct_t*type) -{ - ivl_assert(*this, struct_type_ == 0); - ivl_assert(*this, enumeration_ == 0); - struct_type_ = type; -} - ivl_discipline_t NetNet::get_discipline() const { return discipline_; diff --git a/netlist.h b/netlist.h index 5e6d2bd2c..c2a429dd3 100644 --- a/netlist.h +++ b/netlist.h @@ -577,6 +577,9 @@ class NetNet : public NetObj { explicit NetNet(NetScope*s, perm_string n, Type t, long ms, long ls, long s0, long e0); + // This form builds a NetNet from its record definition. + explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type); + virtual ~NetNet(); Type type() const; @@ -604,7 +607,6 @@ class NetNet : public NetObj { void set_enumeration(netenum_t*enum_set); netenum_t*enumeration(void) const; - void set_struct_type(netstruct_t*type); netstruct_t*struct_type(void) const; /* Attach a discipline to the net. */ diff --git a/netstruct.cc b/netstruct.cc index 36ba3353a..63b673bae 100644 --- a/netstruct.cc +++ b/netstruct.cc @@ -18,6 +18,9 @@ */ # include "netstruct.h" +# include + +using namespace std; netstruct_t::netstruct_t() : packed_(false) @@ -27,3 +30,39 @@ netstruct_t::netstruct_t() netstruct_t::~netstruct_t() { } + +void netstruct_t::packed(bool flag) +{ + packed_ = flag; +} + +void netstruct_t::append_member(const netstruct_t::member_t&val) +{ + members_.push_back(val); +} + +const netstruct_t::member_t* netstruct_t::packed_member(perm_string name, unsigned long&off) const +{ + unsigned long count_off = 0; + for (size_t idx = members_.size() ; idx > 0 ; idx -= 1) { + if (members_[idx-1].name == name) { + off = count_off; + return &members_[idx-1]; + } + count_off += members_[idx-1].width(); + } + + return 0; +} + +long netstruct_t::packed_width(void) const +{ + if (! packed_) + return -1; + + long res = 0; + for (size_t idx = 0 ; idx < members_.size() ; idx += 1) + res += members_[idx].width(); + + return res; +} diff --git a/netstruct.h b/netstruct.h index 48bdd0cc0..6dc3a439f 100644 --- a/netstruct.h +++ b/netstruct.h @@ -20,15 +20,51 @@ */ # include "LineInfo.h" +# include +# include "ivl_target.h" class netstruct_t : public LineInfo { + public: + struct member_t { + perm_string name; + ivl_variable_type_t type; + long msb; + long lsb; + long width() const; + }; + public: netstruct_t(); ~netstruct_t(); + void packed(bool flag); + bool packed(void) const; + + void append_member(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 + // the packed value where the member begins. + const struct member_t* packed_member(perm_string name, unsigned long&off) const; + + // Return the width (in bits) of the packed record, or -1 if + // the record is not packed. + long packed_width() const; + private: bool packed_; + std::vectormembers_; }; +inline bool netstruct_t::packed(void) const { return packed_; } + +inline long netstruct_t::member_t::width() const +{ + if (msb >= lsb) + return msb - lsb + 1; + else + return lsb - msb + 1; +} + #endif diff --git a/parse.y b/parse.y index 9e0a65ef9..16d95dd7b 100644 --- a/parse.y +++ b/parse.y @@ -927,6 +927,7 @@ struct_union_member_list } | struct_union_member { list*tmp = new list; + tmp->push_back($1); $$ = tmp; } ; diff --git a/t-dll.cc b/t-dll.cc index 676ae5f27..c9b3f7024 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2503,7 +2503,7 @@ void dll_target::signal(const NetNet*net) obj->array_words = net->array_count(); obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0; - assert(obj->array_words == net->pin_count()); + ivl_assert(*net, obj->array_words == net->pin_count()); if (debug_optimizer && obj->array_words > 1000) cerr << "debug: " "t-dll creating nexus array " << obj->array_words << " long" << endl; if (obj->array_words > 1 && net->pins_are_virtual()) {