diff --git a/PExpr.h b/PExpr.h index 7121e00f1..714778994 100644 --- a/PExpr.h +++ b/PExpr.h @@ -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; }; diff --git a/elab_lval.cc b/elab_lval.cc index d1f373a17..a49241b86 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -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; } diff --git a/elaborate.cc b/elaborate.cc index 456295799..4aa898d5c 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -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; diff --git a/emit.cc b/emit.cc index 02f2e729c..b49df2168 100644 --- a/emit.cc +++ b/emit.cc @@ -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; diff --git a/net_assign.cc b/net_assign.cc index 0562fb1e5..a47e9b1f7 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -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.". If this is "a.b" (no - // member/property reference, then return width==1. If this is - // "a.b.", then get the type of the 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 (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(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(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 (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 (sig_->net_type())) { + if (const netdarray_t*darray = dynamic_cast (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(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; } diff --git a/netlist.h b/netlist.h index b176b12b9..d3f31dd1d 100644 --- a/netlist.h +++ b/netlist.h @@ -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_; diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 1bb369efd..fb2cffcca 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -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; } diff --git a/t-dll.cc b/t-dll.cc index dbed79f2a..d28d44c48 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -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; } diff --git a/t-dll.h b/t-dll.h index 103c84272..d2c958000 100644 --- a/t-dll.h +++ b/t-dll.h @@ -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); diff --git a/target.h b/target.h index 69642ac64..cf87bea9d 100644 --- a/target.h +++ b/target.h @@ -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;