Elaborate nested l-values.

This gets nested l-values to (but just short of) the ivl_target API.
Now the elaborator can process nested l-values, but I haven't figured
out how to present that at the ivl_target.h API.
This commit is contained in:
Stephen Williams 2013-11-16 16:27:05 -08:00
parent 9bd9c8f301
commit 68d83383ff
10 changed files with 167 additions and 46 deletions

View File

@ -510,6 +510,8 @@ class PEIdent : public PExpr {
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
bool bidirectional_flag) const;
NetAssign_*scan_lname_for_nested_members_(Design*des, NetScope*scope,
const pform_name_t&path) const;
bool eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
long&midx, long&lidx) const;
};

View File

@ -148,6 +148,44 @@ NetAssign_* PEConcat::elaborate_lval(Design*des,
return res;
}
NetAssign_*PEIdent::scan_lname_for_nested_members_(Design*des, NetScope*scope,
const pform_name_t&cur_path) const
{
if (cur_path.size() == 1)
return 0;
pform_name_t use_path = cur_path;
perm_string tmp_name = peek_tail_name(use_path);
use_path.pop_back();
NetNet* reg = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
symbol_search(this, des, scope, use_path, reg, par, eve);
if (reg == 0) {
NetAssign_*tmp = scan_lname_for_nested_members_(des, scope, use_path);
if (tmp == 0)
return 0;
tmp = new NetAssign_(tmp);
tmp->set_property(tmp_name);
return tmp;
}
if (reg->struct_type()) {
cerr << get_fileline() << ": sorry: "
<< "I don't know what to do with struct " << use_path << endl;
return 0;
}
if (reg->class_type()) {
return elaborate_lval_net_class_member_(des, scope, reg, tmp_name);
}
return 0;
}
/*
* Handle the ident as an l-value. This includes bit and part selects
* of that ident.
@ -194,6 +232,9 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
} else if (reg && reg->class_type()) {
method_name = tmp_name;
} else if (NetAssign_*subl = scan_lname_for_nested_members_(des, use_scope, path_)) {
return subl;
} else {
reg = 0;
}

View File

@ -2392,7 +2392,7 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
static bool lval_not_program_variable(const NetAssign_*lv)
{
while (lv) {
NetScope*sig_scope = lv->sig()->scope();
NetScope*sig_scope = lv->scope();
if (! sig_scope->program_block() && sig_scope->type()!=NetScope::CLASS)
return true;

11
emit.cc
View File

@ -527,6 +527,15 @@ int Design::emit(struct target_t*tgt) const
for (const NetAnalogTop*idx = aprocs_ ; idx ; idx = idx->next_)
proc_rc &= idx->emit(tgt);
if (nodes_rc == false)
tgt->errors += 1;
if (tasks_rc == false)
tgt->errors += 1;
if (proc_rc == false)
tgt->errors += 1;
if (branches_rc == false)
tgt->errors += 1;
rc = tgt->end_design(this);
if (nodes_rc == false)
@ -534,7 +543,7 @@ int Design::emit(struct target_t*tgt) const
if (tasks_rc == false)
return -2;
if (proc_rc == false)
return -3;
return -3;
if (branches_rc == false)
return -4;

View File

@ -22,6 +22,7 @@
# include "netlist.h"
# include "netclass.h"
# include "netdarray.h"
# include "netenum.h"
# include "ivl_assert.h"
/*
@ -38,8 +39,14 @@ unsigned count_lval_width(const NetAssign_*idx)
return wid;
}
NetAssign_::NetAssign_(NetAssign_*n)
: nest_(n), sig_(0), word_(0), base_(0), sel_type_(IVL_SEL_OTHER)
{
more = 0;
}
NetAssign_::NetAssign_(NetNet*s)
: sig_(s), word_(0), base_(0), sel_type_(IVL_SEL_OTHER)
: nest_(0), sig_(s), word_(0), base_(0), sel_type_(IVL_SEL_OTHER)
{
lwid_ = sig_->vector_width();
sig_->incr_lref();
@ -59,6 +66,18 @@ NetAssign_::~NetAssign_()
delete word_;
}
string NetAssign_::get_fileline() const
{
if (sig_) return sig_->get_fileline();
else return nest_->get_fileline();
}
NetScope*NetAssign_::scope() const
{
if (sig_) return sig_->scope();
else return nest_->scope();
}
void NetAssign_::set_word(NetExpr*r)
{
assert(word_ == 0);
@ -87,55 +106,65 @@ ivl_select_type_t NetAssign_::select_type() const
unsigned NetAssign_::lwidth() const
{
// If the signal is a class type, then the situation is either
// "a.b" or "a.b.<member>". If this is "a.b" (no
// member/property reference, then return width==1. If this is
// "a.b.<member>", then get the type of the <member> property
// and return the width of that.
if (const netclass_t*class_type = sig_->class_type()) {
if (member_.nil())
return 1;
// This gets me the type of the l-value expression, down to
// the type of the member. If this returns nil, then resort to
// the lwid_ value.
ivl_type_t ntype = net_type();
if (ntype == 0)
return lwid_;
int pidx = class_type->property_idx_from_name(member_);
ivl_assert(*sig_, pidx >= 0);
ivl_type_t ptype = class_type->get_prop_type(pidx);
return ptype->packed_width();
}
if (const netdarray_t*darray = sig_->darray_type()) {
// If the type is a darray, and there is a word index, then we
// actually want the width of the elements.
if (const netdarray_t*darray = dynamic_cast<const netdarray_t*> (ntype)) {
if (word_ == 0)
return 1;
else
return darray->element_width();
}
return lwid_;
return ntype->packed_width();
}
ivl_variable_type_t NetAssign_::expr_type() const
{
if (const netclass_t*class_type = sig_->class_type()) {
if (member_.nil())
return sig_->data_type();
int pidx = class_type->property_idx_from_name(member_);
ivl_assert(*sig_, pidx >= 0);
ivl_type_t tmp = class_type->get_prop_type(pidx);
return tmp->base_type();
}
if (const netdarray_t*darray = sig_->darray_type()) {
ivl_type_t ntype = net_type();
if (const netdarray_t*darray = dynamic_cast<const netdarray_t*>(ntype)) {
if (word_ == 0)
return IVL_VT_DARRAY;
else
return darray->element_base_type();
}
if (ntype) return ntype->base_type();
ivl_assert(*this, sig_);
return sig_->data_type();
}
const ivl_type_s* NetAssign_::net_type() const
{
if (nest_) {
const ivl_type_s*ntype = nest_->net_type();
if (member_.nil())
return ntype;
if (const netclass_t*class_type = dynamic_cast<const netclass_t*>(ntype)) {
int pidx = class_type->property_idx_from_name(member_);
ivl_assert(*this, pidx >= 0);
ivl_type_t tmp = class_type->get_prop_type(pidx);
return tmp;
}
if (const netdarray_t*darray = dynamic_cast<const netdarray_t*> (ntype)) {
if (word_ == 0)
return ntype;
else
return darray->element_type();
}
return 0;
}
if (const netclass_t*class_type = sig_->class_type()) {
if (member_.nil())
return sig_->net_type();
@ -146,11 +175,11 @@ const ivl_type_s* NetAssign_::net_type() const
return tmp;
}
if (dynamic_cast<const netdarray_t*> (sig_->net_type())) {
if (const netdarray_t*darray = dynamic_cast<const netdarray_t*> (sig_->net_type())) {
if (word_ == 0)
return sig_->net_type();
return 0;
else
return darray->element_type();
}
return 0;
@ -159,10 +188,20 @@ const ivl_type_s* NetAssign_::net_type() const
const netenum_t*NetAssign_::enumeration() const
{
const netenum_t*tmp = 0;
ivl_type_t ntype = net_type();
if (ntype == 0) {
// If the base signal is not an enumeration, return nil.
if ( (tmp = sig_->enumeration()) == 0 )
return 0;
ivl_assert(*this, sig_);
// If the base signal is not an enumeration, return nil.
if ( (tmp = sig_->enumeration()) == 0 )
return 0;
} else {
tmp = dynamic_cast<const netenum_t*>(ntype);
if (tmp == 0)
return 0;
}
// Part select of an enumeration is not an enumeration.
if (base_ != 0)
@ -199,7 +238,7 @@ void NetAssign_::set_part(NetExpr*base, unsigned wid,
void NetAssign_::set_property(const perm_string&mname)
{
ivl_assert(*sig_, sig_->class_type());
//ivl_assert(*sig_, sig_->class_type());
member_ = mname;
}

View File

@ -2545,14 +2545,21 @@ class NetAlloc : public NetProc {
class NetAssign_ {
public:
NetAssign_(NetNet*sig);
explicit NetAssign_(NetAssign_*nest);
explicit NetAssign_(NetNet*sig);
~NetAssign_();
// This is so NetAssign_ objects can be passed to ivl_assert
// and other macros that call this method.
string get_fileline() const;
// If this expression exists, then it is used to select a word
// from an array/memory.
NetExpr*word();
const NetExpr*word() const;
NetScope*scope()const;
// Get the base index of the part select, or 0 if there is no
// part select.
const NetExpr* get_base() const;
@ -2609,6 +2616,8 @@ class NetAssign_ {
void dump_lval(ostream&o) const;
private:
// Nested l-value. If this is set, sig_ mut NOT be setl
NetAssign_*nest_;
NetNet *sig_;
// Memory word index
NetExpr*word_;

View File

@ -136,8 +136,9 @@ bool dll_target::func_def(const NetScope*net)
* This private function makes the assignment lvals for the various
* kinds of assignment statements.
*/
void dll_target::make_assign_lvals_(const NetAssignBase*net)
bool dll_target::make_assign_lvals_(const NetAssignBase*net)
{
bool flag = true;
assert(stmt_cur_);
unsigned cnt = net->l_val_count();
@ -188,9 +189,14 @@ void dll_target::make_assign_lvals_(const NetAssignBase*net)
}
} else {
assert(0);
cerr << net->get_fileline() << ": internal error: "
<< "I don't know how to handle nested l-values "
<< "in ivl_target.h API." << endl;
flag = false;
}
}
return flag;
}
void dll_target::proc_alloc(const NetAlloc*net)
@ -207,6 +213,8 @@ void dll_target::proc_alloc(const NetAlloc*net)
*/
bool dll_target::proc_assign(const NetAssign*net)
{
bool flag = true;
assert(stmt_cur_);
assert(stmt_cur_->type_ == IVL_ST_NONE);
@ -216,7 +224,7 @@ bool dll_target::proc_assign(const NetAssign*net)
stmt_cur_->u_.assign_.delay = 0;
/* Make the lval fields. */
make_assign_lvals_(net);
flag &= make_assign_lvals_(net);
stmt_cur_->u_.assign_.oper = net->assign_operator();
assert(expr_ == 0);
@ -231,7 +239,7 @@ bool dll_target::proc_assign(const NetAssign*net)
expr_ = 0;
}
return true;
return flag;
}

View File

@ -710,11 +710,20 @@ bool dll_target::start_design(const Design*des)
*/
int dll_target::end_design(const Design*)
{
if (verbose_flag) {
cout << " ... invoking target_design" << endl;
int rc;
if (errors == 0) {
if (verbose_flag) {
cout << " ... invoking target_design" << endl;
}
rc = (target_)(&des_);
} else {
if (verbose_flag) {
cout << " ... skipping target_design due to errors." << endl;
}
rc = errors;
}
int rc = (target_)(&des_);
ivl_dlclose(dll_);
return rc;
}

View File

@ -172,7 +172,7 @@ struct dll_target : public target_t, public expr_scan_t {
void add_root(const NetScope *s);
void make_assign_lvals_(const NetAssignBase*net);
bool make_assign_lvals_(const NetAssignBase*net);
void sub_off_from_expr_(long);
void mul_expr_by_const_(long);

View File

@ -46,8 +46,12 @@ struct target {
*/
struct target_t {
inline target_t() : errors(0) { }
virtual ~target_t();
/* Set this to count errors encountered during emit. */
int errors;
/* Start the design. This sets the main output file stream
that the target should use. */
virtual bool start_design(const Design*) =0;