Handle members of packed struct as implicit part selects.
Packed struct members are synonymous with part selects, but in a much more convenient form, so get them to work that way.
This commit is contained in:
parent
d362c8dba0
commit
3a2866b57c
28
elab_expr.cc
28
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 " <<mem->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,
|
||||
|
|
|
|||
97
elab_sig.cc
97
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<struct_member_t*>::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<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.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 << " ["<<msb<<":"<<lsb<<"]";
|
||||
|
||||
NetNet*sig = 0;
|
||||
|
||||
// If this is a struct type, then build the net with the
|
||||
// struct type.
|
||||
if (struct_type_) {
|
||||
netstruct_t*use_type = elaborate_struct_type(des, scope, struct_type_);
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal " << wtype;
|
||||
if (use_type->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 << " ["<<msb<<":"<<lsb<<"]";
|
||||
}
|
||||
cerr << " " << name_;
|
||||
if (array_dimensions > 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<named_pexpr_t>::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_;
|
||||
|
|
|
|||
53
netlist.cc
53
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_;
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
39
netstruct.cc
39
netstruct.cc
|
|
@ -18,6 +18,9 @@
|
|||
*/
|
||||
|
||||
# include "netstruct.h"
|
||||
# include <iostream>
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
36
netstruct.h
36
netstruct.h
|
|
@ -20,15 +20,51 @@
|
|||
*/
|
||||
|
||||
# include "LineInfo.h"
|
||||
# include <vector>
|
||||
# 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::vector<member_t>members_;
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
|||
1
parse.y
1
parse.y
|
|
@ -927,6 +927,7 @@ struct_union_member_list
|
|||
}
|
||||
| struct_union_member
|
||||
{ list<struct_member_t*>*tmp = new list<struct_member_t*>;
|
||||
tmp->push_back($1);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
|
|
|||
2
t-dll.cc
2
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()) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue