From 9fa764285a423864c1261de917a137ee25fdefca Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 25 Aug 2014 14:58:57 -0700 Subject: [PATCH 01/13] foreach multiple indices through the pform. --- Statement.cc | 8 ++++++-- Statement.h | 4 ++-- elaborate.cc | 8 +++++++- pform.cc | 15 +++++++-------- pform_dump.cc | 9 +++++++-- 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/Statement.cc b/Statement.cc index f0a395fd8..e0ed46d24 100644 --- a/Statement.cc +++ b/Statement.cc @@ -336,9 +336,13 @@ PForce::~PForce() delete expr_; } -PForeach::PForeach(perm_string av, perm_string ix, Statement*s) -: array_var_(av), index_var_(ix), statement_(s) +PForeach::PForeach(perm_string av, const list&ix, Statement*s) +: array_var_(av), index_vars_(ix.size()), statement_(s) { + size_t idx = 0; + for (list::const_iterator cur = ix.begin() + ; cur != ix.end() ; ++cur) + index_vars_[idx++] = *cur; } PForeach::~PForeach() diff --git a/Statement.h b/Statement.h index a3f17a1fa..b37188c0f 100644 --- a/Statement.h +++ b/Statement.h @@ -445,7 +445,7 @@ class PForce : public Statement { class PForeach : public Statement { public: - explicit PForeach(perm_string var, perm_string ix, Statement*stmt); + explicit PForeach(perm_string var, const std::list&ix, Statement*stmt); ~PForeach(); virtual NetProc* elaborate(Design*des, NetScope*scope) const; @@ -455,7 +455,7 @@ class PForeach : public Statement { private: perm_string array_var_; - perm_string index_var_; + std::vector index_vars_; Statement*statement_; }; diff --git a/elaborate.cc b/elaborate.cc index 4413f22de..b03ec3592 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4591,9 +4591,15 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const */ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const { + if (index_vars_.size() != 1) { + cerr << get_fileline() << ": sorry: " + << "Multi-index foreach loops not supported." << endl; + des->errors += 1; + } + // Get the signal for the index variable. pform_name_t index_name; - index_name.push_back(name_component_t(index_var_)); + index_name.push_back(name_component_t(index_vars_[0])); NetNet*idx_sig = des->find_signal(scope, index_name); ivl_assert(*this, idx_sig); diff --git a/pform.cc b/pform.cc index 68e9a072d..1b05d7c2a 100644 --- a/pform.cc +++ b/pform.cc @@ -728,19 +728,18 @@ PForeach* pform_make_foreach(const struct vlltype&loc, perm_string use_name = lex_strings.make(name); delete[]name; - perm_string use_index = loop_vars->front(); - loop_vars->pop_front(); - - if (! loop_vars->empty()) { - cerr << loc.get_fileline() << ": sorry: " - << "Multi-dimension foreach indices not supported." << endl; + if (loop_vars==0 || loop_vars->empty()) { + cerr << loc.get_fileline() << ": error: " + << "No loop variables at all in foreach index." << endl; error_count += 1; } - delete loop_vars; - PForeach*fe = new PForeach(use_name, use_index, stmt); + ivl_assert(loc, loop_vars); + PForeach*fe = new PForeach(use_name, *loop_vars, stmt); FILE_NAME(fe, loc); + delete loop_vars; + return fe; } diff --git a/pform_dump.cc b/pform_dump.cc index c7560ea9a..f50749f31 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -973,8 +973,13 @@ void PForeach::dump(ostream&fd, unsigned ind) const { fd << setw(ind) << "" << "foreach " << "variable=" << array_var_ - << ", index=" << index_var_ - << " /* " << get_fileline() << " */" << endl; + << ", indices=["; + for (size_t idx = 0 ; idx < index_vars_.size() ; idx += 1) { + if (idx > 0) fd << ","; + fd << index_vars_[idx]; + } + + fd << "] /* " << get_fileline() << " */" << endl; statement_->dump(fd, ind+3); } From 0cd6fbaf41fd16a4a8f02d883c5965e4d35122e3 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 25 Aug 2014 17:10:26 -0700 Subject: [PATCH 02/13] foreach loops around static arrays Arrays with static dimensions can be handled specially. This also allows for arbitrary numbers of dimensions. --- Statement.h | 4 +++ elaborate.cc | 94 +++++++++++++++++++++++++++++++++++++++++++++++----- netmisc.cc | 8 +++++ netmisc.h | 1 + 4 files changed, 98 insertions(+), 9 deletions(-) diff --git a/Statement.h b/Statement.h index b37188c0f..1785d9b6f 100644 --- a/Statement.h +++ b/Statement.h @@ -453,6 +453,10 @@ class PForeach : public Statement { virtual void elaborate_sig(Design*des, NetScope*scope) const; virtual void dump(ostream&out, unsigned ind) const; + private: + NetProc* elaborate_static_array_(Design*des, NetScope*scope, + NetNet*array_sig) const; + private: perm_string array_var_; std::vector index_vars_; diff --git a/elaborate.cc b/elaborate.cc index b03ec3592..a09a3403f 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4591,6 +4591,25 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const */ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const { + // Get the signal for the array variable + pform_name_t array_name; + array_name.push_back(name_component_t(array_var_)); + NetNet*array_sig = des->find_signal(scope, array_name); + ivl_assert(*this, array_sig); + + if (debug_elaborate) { + cerr << get_fileline() << ": PForeach::elaborate: " + << "Scan array " << array_sig->name() + << " with " << array_sig->unpacked_dims().size() << " unpacked" + << " and " << array_sig->packed_dims().size() + << " packed dimensions." << endl; + } + + if (array_sig->data_type()==IVL_VT_BOOL) + return elaborate_static_array_(des, scope, array_sig); + if (array_sig->data_type()==IVL_VT_LOGIC) + return elaborate_static_array_(des, scope, array_sig); + if (index_vars_.size() != 1) { cerr << get_fileline() << ": sorry: " << "Multi-index foreach loops not supported." << endl; @@ -4603,18 +4622,12 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const NetNet*idx_sig = des->find_signal(scope, index_name); ivl_assert(*this, idx_sig); - NetESignal*idx_exp = new NetESignal(idx_sig); - idx_exp->set_line(*this); - - // Get the signal for the array variable - pform_name_t array_name; - array_name.push_back(name_component_t(array_var_)); - NetNet*array_sig = des->find_signal(scope, array_name); - ivl_assert(*this, array_sig); - NetESignal*array_exp = new NetESignal(array_sig); array_exp->set_line(*this); + NetESignal*idx_exp = new NetESignal(idx_sig); + idx_exp->set_line(*this); + // Make an initialization expression for the index. NetESFunc*init_expr = new NetESFunc("$low", IVL_VT_BOOL, 32, 1); init_expr->set_line(*this); @@ -4645,6 +4658,69 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const return stmt; } +/* + * This is a variant of the PForeach::elaborate() method that handles + * the case that the array has static dimensions. We can use constants + * and possibly do some optimizations. + */ +NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, + NetNet*array_sig) const +{ + if (debug_elaborate) { + cerr << get_fileline() << ": PForeach::elaborate_static_array_: " + << "Handle as array with static dimensions." << endl; + } + + ivl_assert(*this, index_vars_.size() > 0); + ivl_assert(*this, array_sig->unpacked_dims().size() == index_vars_.size()); + + NetProc*sub = statement_->elaborate(des, scope); + NetForLoop*stmt = 0; + + for (int idx_idx = index_vars_.size()-1 ; idx_idx >= 0 ; idx_idx -= 1) { + const netrange_t&idx_range = array_sig->unpacked_dims()[idx_idx]; + + // Get the $high and $low constant values for this slice + // of the array. + NetEConst*hig_expr = make_const_val_s(idx_range.get_msb()); + NetEConst*low_expr = make_const_val_s(idx_range.get_lsb()); + if (idx_range.get_msb() < idx_range.get_lsb()) { + NetEConst*tmp = hig_expr; + hig_expr = low_expr; + low_expr = tmp; + } + + hig_expr->set_line(*this); + low_expr->set_line(*this); + + pform_name_t idx_name; + idx_name.push_back(name_component_t(index_vars_[idx_idx])); + NetNet*idx_sig = des->find_signal(scope, idx_name); + ivl_assert(*this, idx_sig); + + // Make the condition expression <= $high(slice) + NetESignal*idx_expr = new NetESignal(idx_sig); + idx_expr->set_line(*this); + + NetEBComp*cond_expr = new NetEBComp('L', idx_expr, hig_expr); + cond_expr->set_line(*this); + + // Make the step statement: += 1 + NetAssign_*idx_lv = new NetAssign_(idx_sig); + NetEConst*step_val = make_const_val_s(1); + NetAssign*step = new NetAssign(idx_lv, '+', step_val); + step->set_line(*this); + + stmt = new NetForLoop(idx_sig, low_expr, cond_expr, sub, step); + stmt->set_line(*this); + stmt->wrap_up(); + + sub = stmt; + } + + return stmt? stmt : sub; +} + /* * elaborate the for loop as the equivalent while loop. This eases the * task for the target code generator. The structure is: diff --git a/netmisc.cc b/netmisc.cc index 585388f06..e4928ad76 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -667,6 +667,14 @@ NetEConst* make_const_val(unsigned long value) return res; } +NetEConst* make_const_val_s(long value) +{ + verinum tmp (value, integer_width); + tmp.has_sign(true); + NetEConst*res = new NetEConst(tmp); + return res; +} + NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid) { verinum xxx (verinum::Vx, wid); diff --git a/netmisc.h b/netmisc.h index 6b5db586f..3e682fdd2 100644 --- a/netmisc.h +++ b/netmisc.h @@ -204,6 +204,7 @@ extern NetNet*sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig); extern NetEConst*make_const_x(unsigned long wid); extern NetEConst*make_const_0(unsigned long wid); extern NetEConst*make_const_val(unsigned long val); +extern NetEConst*make_const_val_s(long val); /* * Make A const net From dec4cd5071fa544abc3e4c2bd709ccacf60e0bba Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 29 Aug 2014 20:31:51 -0700 Subject: [PATCH 03/13] Handle arrays of class objects. This goes all the way down to the vvp level, where we create support for arrays of objects, generate the new code in the -tvvp code generator, and elaborate the arrays in the first place. --- elab_expr.cc | 68 +++++++++++++++++++++++++++++++++++++++++-- elab_sig.cc | 9 +++--- elaborate.cc | 8 +++-- tgt-vvp/eval_expr.c | 12 +++++++- tgt-vvp/eval_object.c | 21 +++++++++++-- tgt-vvp/stmt_assign.c | 14 ++++++++- tgt-vvp/vvp_scope.c | 4 +++ vvp/array.cc | 51 ++++++++++++++++++++++++++++++++ vvp/array.h | 3 ++ vvp/codes.h | 3 ++ vvp/compile.cc | 3 ++ vvp/compile.h | 2 ++ vvp/lexor.lex | 1 + vvp/parse.y | 5 +++- vvp/vthread.cc | 55 ++++++++++++++++++++++++++++++++++ vvp/vvp_darray.cc | 36 +++++++++++++++++++++++ vvp/vvp_darray.h | 16 ++++++++++ 17 files changed, 296 insertions(+), 15 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 30ade72ac..da4bf6c82 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3113,8 +3113,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, - ivl_type_t ntype, unsigned) const + ivl_type_t ntype, unsigned flags) const { + bool need_const = NEED_CONST & flags; + NetNet* net = 0; const NetExpr*par = 0; NetEvent* eve = 0; @@ -3185,7 +3187,69 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, } ivl_assert(*this, ntype->type_compatible(net->net_type())); - NetESignal*tmp = new NetESignal(net); + const name_component_t&use_comp = path_.back(); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr: " + << "Typed ident " << net->name() + << " with " << use_comp.index.size() << " indices" + << " and " << net->unpacked_dimensions() << " expected." + << endl; + } + + if (net->unpacked_dimensions() != use_comp.index.size()) { + cerr << get_fileline() << ": sorry: " + << "Net " << net->name() + << " expects " << net->unpacked_dimensions() + << ", but got " << use_comp.index.size() << "." + << endl; + des->errors += 1; + + NetESignal*tmp = new NetESignal(net); + tmp->set_line(*this); + return tmp; + } + + if (net->unpacked_dimensions() == 0) { + NetESignal*tmp = new NetESignal(net); + tmp->set_line(*this); + return tmp; + } + + // Convert a set of index expressions to a single expression + // that addresses the canonical element. + listunpacked_indices; + list unpacked_indices_const; + indices_flags idx_flags; + indices_to_expressions(des, scope, this, + use_comp.index, net->unpacked_dimensions(), + need_const, + idx_flags, + unpacked_indices, + unpacked_indices_const); + + NetExpr*canon_index = 0; + + if (idx_flags.invalid) { + // Nothing to do + + } else if (idx_flags.undefined) { + cerr << get_fileline() << ": warning: " + << "returning 'bx for undefined array access " + << net->name() << as_indices(unpacked_indices) + << "." << endl; + + } else if (idx_flags.variable) { + ivl_assert(*this, unpacked_indices.size() == net->unpacked_dimensions()); + canon_index = normalize_variable_unpacked(net, unpacked_indices); + + } else { + ivl_assert(*this, unpacked_indices_const.size() == net->unpacked_dimensions()); + canon_index = normalize_variable_unpacked(net, unpacked_indices_const); + } + + ivl_assert(*this, canon_index); + NetESignal*tmp = new NetESignal(net, canon_index); tmp->set_line(*this); return tmp; diff --git a/elab_sig.cc b/elab_sig.cc index e88689a14..37c10f0b8 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1222,13 +1222,12 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } ivl_assert(*this, use_type); if (debug_elaborate) { - cerr << get_fileline() << ": debug: " + cerr << get_fileline() << ": PWire::elaborate_sig: " << "Create class instance signal " << wtype - << " " << name_ << endl; + << " " << packed_dimensions << name_ << unpacked_dimensions << endl; } - // (No arrays of classes) - list use_unpacked; - sig = new NetNet(scope, name_, wtype, use_unpacked, use_type); + + sig = new NetNet(scope, name_, wtype, unpacked_dimensions, use_type); } else if (struct_type_t*struct_type = dynamic_cast(set_data_type_)) { // If this is a struct type, then build the net with the diff --git a/elaborate.cc b/elaborate.cc index a09a3403f..c8e801a5f 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4600,15 +4600,19 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": PForeach::elaborate: " << "Scan array " << array_sig->name() - << " with " << array_sig->unpacked_dims().size() << " unpacked" - << " and " << array_sig->packed_dims().size() + << " of " << array_sig->data_type() + << " with " << array_sig->unpacked_dimensions() << " unpacked" + << " and " << array_sig->packed_dimensions() << " packed dimensions." << endl; } + // Classic arrays are processed this way. if (array_sig->data_type()==IVL_VT_BOOL) return elaborate_static_array_(des, scope, array_sig); if (array_sig->data_type()==IVL_VT_LOGIC) return elaborate_static_array_(des, scope, array_sig); + if (array_sig->unpacked_dimensions() >= index_vars_.size()) + return elaborate_static_array_(des, scope, array_sig); if (index_vars_.size() != 1) { cerr << get_fileline() << ": sorry: " diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 7d8ed5d25..d4028dddf 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -519,7 +519,17 @@ static struct vector_info draw_binary_expr_eq_class(ivl_expr_t expr) } if (ivl_expr_type(re) == IVL_EX_NULL && ivl_expr_type(le)==IVL_EX_SIGNAL) { - fprintf(vvp_out, " %%test_nul v%p_0;\n", ivl_expr_signal(le)); + ivl_signal_t sig = ivl_expr_signal(le); + + if (ivl_signal_dimensions(sig) == 0) { + fprintf(vvp_out, " %%test_nul v%p_0;\n", sig); + } else { + ivl_expr_t word_ex = ivl_expr_oper1(le); + int word_ix = allocate_word(); + draw_eval_expr_into_integer(word_ex, word_ix); + fprintf(vvp_out, " %%test_nula v%p, %d;\n", sig, word_ix); + clr_word(word_ix); + } fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base); if (ivl_expr_opcode(expr) == 'n') fprintf(vvp_out, " %%inv %u, 1;\n", res.base); diff --git a/tgt-vvp/eval_object.c b/tgt-vvp/eval_object.c index 01019a0a6..883eeeb57 100644 --- a/tgt-vvp/eval_object.c +++ b/tgt-vvp/eval_object.c @@ -195,10 +195,25 @@ static int eval_object_shallowcopy(ivl_expr_t ex) return 0; } -static int eval_object_signal(ivl_expr_t ex) +static int eval_object_signal(ivl_expr_t expr) { - ivl_signal_t sig = ivl_expr_signal(ex); - fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + ivl_signal_t sig = ivl_expr_signal(expr); + + /* Simple case: This is a simple variable. Generate a load + statement to load the string into the stack. */ + if (ivl_signal_dimensions(sig) == 0) { + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + return 0; + } + + /* There is a word select expression, so load the index into a + register and load from the array. */ + ivl_expr_t word_ex = ivl_expr_oper1(expr); + int word_ix = allocate_word(); + draw_eval_expr_into_integer(word_ex, word_ix); + fprintf(vvp_out, " %%load/obja v%p, %d;\n", sig, word_ix); + clr_word(word_ix); + return 0; } diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index c05bd1fe1..74ffde30c 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -1066,7 +1066,19 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) as an object and assign the entire object to the variable. */ errors += draw_eval_object(rval); - fprintf(vvp_out, " %%store/obj v%p_0;\n", sig); + + if (ivl_signal_array_count(sig) > 1) { + unsigned ix; + ivl_expr_t aidx = ivl_lval_idx(lval); + + draw_eval_expr_into_integer(aidx, (ix = allocate_word())); + fprintf(vvp_out, " %%store/obja v%p, %u;\n", sig, ix); + clr_word(ix); + + } else { + /* Not an array, so no index expression */ + fprintf(vvp_out, " %%store/obj v%p_0;\n", sig); + } } return errors; diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index a41db91b3..b2779f379 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -469,6 +469,10 @@ static void draw_reg_in_scope(ivl_signal_t sig) datatype_flag = "/str"; vector_dims = 0; break; + case IVL_VT_CLASS: + datatype_flag = "/obj"; + vector_dims = 0; + break; default: break; } diff --git a/vvp/array.cc b/vvp/array.cc index 25bfdbf3d..396b7effe 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -1055,6 +1055,18 @@ void array_set_word(vvp_array_t arr, unsigned address, const string&val) array_word_change(arr, address); } +void array_set_word(vvp_array_t arr, unsigned address, const vvp_object_t&val) +{ + assert(arr->vals != 0); + assert(arr->nets == 0); + + if (address >= arr->vals->get_size()) + return; + + arr->vals->set_word(address, val); + array_word_change(arr, address); +} + vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) { if (arr->vals4) { @@ -1129,6 +1141,28 @@ double array_get_word_r(vvp_array_t arr, unsigned address) } +void array_get_word_obj(vvp_array_t arr, unsigned address, vvp_object_t&val) +{ + if (arr->vals) { + assert(arr->vals4 == 0); + assert(arr->nets == 0); + // In this context, address out of bounds returns 0.0 + // instead of an error. + if (address >= arr->vals->get_size()) { + val = vvp_object_t(); + return; + } + + arr->vals->get_word(address, val); + return; + } + + assert(arr->nets); + // Arrays of string nets not implemented! + assert(0); + return; +} + string array_get_word_str(vvp_array_t arr, unsigned address) { if (arr->vals) { @@ -1354,6 +1388,23 @@ void compile_string_array(char*label, char*name, int last, int first) delete[] name; } +void compile_object_array(char*label, char*name, int last, int first) +{ + vpiHandle obj = vpip_make_array(label, name, first, last, true); + + struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); + + /* Make the words. */ + arr->vals = new vvp_darray_object(arr->array_count); + arr->vals_width = 1; + + count_real_arrays += 1; + count_real_array_words += arr->array_count; + + free(label); + delete[] name; +} + void compile_net_array(char*label, char*name, int last, int first) { // At this point we don't know the array data type, so we diff --git a/vvp/array.h b/vvp/array.h index 322852408..d1766ed15 100644 --- a/vvp/array.h +++ b/vvp/array.h @@ -45,9 +45,12 @@ extern void array_set_word(vvp_array_t arr, unsigned idx, double val); extern void array_set_word(vvp_array_t arr, unsigned idx, const std::string&val); +extern void array_set_word(vvp_array_t arr, unsigned idx, + const vvp_object_t&val); extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned address); extern double array_get_word_r(vvp_array_t array, unsigned address); +extern void array_get_word_obj(vvp_array_t array, unsigned address, vvp_object_t&val); extern std::string array_get_word_str(vvp_array_t array, unsigned address); /* VPI hooks */ diff --git a/vvp/codes.h b/vvp/codes.h index d439bf2e0..bbb555c7d 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -133,6 +133,7 @@ extern bool of_LOAD_REAL(vthread_t thr, vvp_code_t code); extern bool of_LOAD_DAR_R(vthread_t thr, vvp_code_t code); extern bool of_LOAD_DAR_STR(vthread_t thr, vvp_code_t code); extern bool of_LOAD_OBJ(vthread_t thr, vvp_code_t code); +extern bool of_LOAD_OBJA(vthread_t thr, vvp_code_t code); extern bool of_LOAD_STR(vthread_t thr, vvp_code_t code); extern bool of_LOAD_STRA(vthread_t thr, vvp_code_t code); extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code); @@ -203,6 +204,7 @@ extern bool of_STORE_QB_STR(vthread_t thr, vvp_code_t code); extern bool of_STORE_QF_R(vthread_t thr, vvp_code_t code); extern bool of_STORE_QF_STR(vthread_t thr, vvp_code_t code); extern bool of_STORE_OBJ(vthread_t thr, vvp_code_t code); +extern bool of_STORE_OBJA(vthread_t thr, vvp_code_t code); extern bool of_STORE_PROP_OBJ(vthread_t thr, vvp_code_t code); extern bool of_STORE_PROP_R(vthread_t thr, vvp_code_t code); extern bool of_STORE_PROP_STR(vthread_t thr, vvp_code_t code); @@ -217,6 +219,7 @@ extern bool of_SUBI(vthread_t thr, vvp_code_t code); extern bool of_SUBSTR(vthread_t thr, vvp_code_t code); extern bool of_SUBSTR_V(vthread_t thr, vvp_code_t code); extern bool of_TEST_NUL(vthread_t thr, vvp_code_t code); +extern bool of_TEST_NULA(vthread_t thr, vvp_code_t code); extern bool of_VPI_CALL(vthread_t thr, vvp_code_t code); extern bool of_WAIT(vthread_t thr, vvp_code_t code); extern bool of_WAIT_FORK(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 4dac7f1de..4115853be 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -180,6 +180,7 @@ static const struct opcode_table_s opcode_table[] = { { "%load/dar/r", of_LOAD_DAR_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE}}, { "%load/dar/str",of_LOAD_DAR_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, { "%load/obj", of_LOAD_OBJ, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, + { "%load/obja", of_LOAD_OBJA,2,{OA_ARR_PTR, OA_BIT1, OA_NONE} }, { "%load/real", of_LOAD_REAL,1,{OA_VPI_PTR, OA_NONE, OA_NONE} }, { "%load/str", of_LOAD_STR, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, { "%load/stra", of_LOAD_STRA,2,{OA_ARR_PTR, OA_BIT1, OA_NONE} }, @@ -246,6 +247,7 @@ static const struct opcode_table_s opcode_table[] = { { "%store/dar/r", of_STORE_DAR_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, { "%store/dar/str",of_STORE_DAR_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, { "%store/obj", of_STORE_OBJ, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} }, + { "%store/obja", of_STORE_OBJA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} }, { "%store/prop/obj",of_STORE_PROP_OBJ,1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%store/prop/r", of_STORE_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%store/prop/str",of_STORE_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} }, @@ -264,6 +266,7 @@ static const struct opcode_table_s opcode_table[] = { { "%substr", of_SUBSTR, 2,{OA_BIT1, OA_BIT2, OA_NONE} }, { "%substr/v",of_SUBSTR_V,3,{OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%test_nul", of_TEST_NUL, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, + { "%test_nula", of_TEST_NULA,2,{OA_ARR_PTR, OA_BIT1, OA_NONE} }, { "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, { "%wait/fork",of_WAIT_FORK,0,{OA_NONE, OA_NONE, OA_NONE} }, { "%xnor", of_XNOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, diff --git a/vvp/compile.h b/vvp/compile.h index c385e76f0..48b4e6247 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -373,6 +373,8 @@ extern void compile_real_array(char*label, char*name, int last, int first); extern void compile_string_array(char*label, char*name, int last, int first); +extern void compile_object_array(char*label, char*name, + int last, int first); extern void compile_net_array(char*label, char*name, int last, int first); extern void compile_array_alias(char*label, char*name, char*src); diff --git a/vvp/lexor.lex b/vvp/lexor.lex index e197928bf..58848bd76 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -124,6 +124,7 @@ static char* strdupnew(char const *str) ".array/2s" { return K_ARRAY_2S; } ".array/2u" { return K_ARRAY_2U; } ".array/i" { return K_ARRAY_I; } +".array/obj" { return K_ARRAY_OBJ; } ".array/real" { return K_ARRAY_R; } ".array/s" { return K_ARRAY_S; } ".array/str" { return K_ARRAY_STR; } diff --git a/vvp/parse.y b/vvp/parse.y index 2a9753e00..97e5e8665 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -77,7 +77,7 @@ static struct __vpiModPath*modpath_dst = 0; %token K_ARITH_MOD_R K_ARITH_MOD_S %token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R %token K_ARITH_SUM K_ARITH_SUM_R K_ARITH_POW K_ARITH_POW_R K_ARITH_POW_S -%token K_ARRAY K_ARRAY_2U K_ARRAY_2S K_ARRAY_I K_ARRAY_R K_ARRAY_S K_ARRAY_STR K_ARRAY_PORT +%token K_ARRAY K_ARRAY_2U K_ARRAY_2S K_ARRAY_I K_ARRAY_OBJ K_ARRAY_R K_ARRAY_S K_ARRAY_STR K_ARRAY_PORT %token K_CAST_INT K_CAST_REAL K_CAST_REAL_S K_CAST_2 %token K_CLASS %token K_CMP_EEQ K_CMP_EQ K_CMP_EQX K_CMP_EQZ @@ -234,6 +234,9 @@ statement | T_LABEL K_ARRAY_STR T_STRING ',' signed_t_number signed_t_number ';' { compile_string_array($1, $3, $5, $6); } + | T_LABEL K_ARRAY_OBJ T_STRING ',' signed_t_number signed_t_number ';' + { compile_object_array($1, $3, $5, $6); } + | T_LABEL K_ARRAY T_STRING ',' signed_t_number signed_t_number ';' { compile_net_array($1, $3, $5, $6); } diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 3a83e20c4..db1d9e08a 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -3531,6 +3531,23 @@ bool of_LOAD_OBJ(vthread_t thr, vvp_code_t cp) return true; } +bool of_LOAD_OBJA(vthread_t thr, vvp_code_t cp) +{ + unsigned idx = cp->bit_idx[0]; + unsigned adr = thr->words[idx].w_int; + vvp_object_t word; + + /* The result is 0.0 if the address is undefined. */ + if (thr_get_bit(thr, 4) == BIT4_1) { + ; // Return nil + } else { + array_get_word_obj(cp->array, adr, word); + } + + thr->push_object(word); + return true; +} + /* * %load/real */ @@ -5444,6 +5461,23 @@ bool of_STORE_OBJ(vthread_t thr, vvp_code_t cp) return true; } +/* + * %store/obja + */ +bool of_STORE_OBJA(vthread_t thr, vvp_code_t cp) +{ + unsigned idx = cp->bit_idx[0]; + unsigned adr = thr->words[idx].w_int; + + vvp_object_t val; + thr->pop_object(val); + + array_set_word(cp->array, adr, val); + + return true; +} + + /* * %store/prop/obj * @@ -5798,6 +5832,27 @@ bool of_TEST_NUL(vthread_t thr, vvp_code_t cp) return true; } +bool of_TEST_NULA(vthread_t thr, vvp_code_t cp) +{ + unsigned idx = cp->bit_idx[0]; + unsigned adr = thr->words[idx].w_int; + vvp_object_t word; + + /* If the address is undefined, return true. */ + if (thr_get_bit(thr, 4) == BIT4_1) { + thr_put_bit(thr, 4, BIT4_1); + return true; + } + + array_get_word_obj(cp->array, adr, word); + if (word.test_nil()) + thr_put_bit(thr, 4, BIT4_1); + else + thr_put_bit(thr, 4, BIT4_0); + + return true; +} + bool of_VPI_CALL(vthread_t thr, vvp_code_t cp) { vpip_execute_vpi_call(thr, cp->handle); diff --git a/vvp/vvp_darray.cc b/vvp/vvp_darray.cc index 9e3e27a8e..247bc0722 100644 --- a/vvp/vvp_darray.cc +++ b/vvp/vvp_darray.cc @@ -43,6 +43,11 @@ void vvp_darray::set_word(unsigned, const string&) cerr << "XXXX set_word(string) not implemented for " << typeid(*this).name() << endl; } +void vvp_darray::set_word(unsigned, const vvp_object_t&) +{ + cerr << "XXXX set_word(vvp_object_t) not implemented for " << typeid(*this).name() << endl; +} + void vvp_darray::get_word(unsigned, vvp_vector4_t&) { cerr << "XXXX get_word(vvp_vector4_t) not implemented for " << typeid(*this).name() << endl; @@ -58,6 +63,11 @@ void vvp_darray::get_word(unsigned, string&) cerr << "XXXX get_word(string) not implemented for " << typeid(*this).name() << endl; } +void vvp_darray::get_word(unsigned, vvp_object_t&) +{ + cerr << "XXXX get_word(vvp_object_t) not implemented for " << typeid(*this).name() << endl; +} + template vvp_darray_atom::~vvp_darray_atom() { } @@ -101,6 +111,32 @@ template class vvp_darray_atom; template class vvp_darray_atom; template class vvp_darray_atom; +vvp_darray_object::~vvp_darray_object() +{ +} + +size_t vvp_darray_object::get_size() const +{ + return array_.size(); +} + +void vvp_darray_object::set_word(unsigned adr, const vvp_object_t&value) +{ + if (adr >= array_.size()) + return; + array_[adr] = value; +} + +void vvp_darray_object::get_word(unsigned adr, vvp_object_t&value) +{ + if (adr >= array_.size()) { + value = vvp_object_t(); + return; + } + + value = array_[adr]; +} + vvp_darray_real::~vvp_darray_real() { } diff --git a/vvp/vvp_darray.h b/vvp/vvp_darray.h index 62f4797b8..54e65ae6c 100644 --- a/vvp/vvp_darray.h +++ b/vvp/vvp_darray.h @@ -42,6 +42,9 @@ class vvp_darray : public vvp_object { virtual void set_word(unsigned adr, const std::string&value); virtual void get_word(unsigned adr, std::string&value); + + virtual void set_word(unsigned adr, const vvp_object_t&value); + virtual void get_word(unsigned adr, vvp_object_t&value); }; template class vvp_darray_atom : public vvp_darray { @@ -86,6 +89,19 @@ class vvp_darray_string : public vvp_darray { std::vector array_; }; +class vvp_darray_object : public vvp_darray { + + public: + inline vvp_darray_object(size_t siz) : array_(siz) { } + ~vvp_darray_object(); + + size_t get_size(void) const; + void set_word(unsigned adr, const vvp_object_t&value); + void get_word(unsigned adr, vvp_object_t&value); + + private: + std::vector array_; +}; class vvp_queue : public vvp_darray { From 0dc28c0fc3d53716fcc0d3a3fe3d9a29aa7ad62f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 29 Aug 2014 20:32:20 -0700 Subject: [PATCH 04/13] Fix the %qpop/f instruction detection. --- vvp/compile.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vvp/compile.cc b/vvp/compile.cc index 4115853be..0ab23b841 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -225,8 +225,8 @@ static const struct opcode_table_s opcode_table[] = { { "%pushv/str", of_PUSHV_STR, 2, {OA_BIT1,OA_BIT2, OA_NONE} }, { "%putc/str/v",of_PUTC_STR_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%qpop/b", of_QPOP_B, 3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, - { "%qpop/f", of_QPOP_F, 3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%qpop/b/str",of_QPOP_B_STR,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, + { "%qpop/f", of_QPOP_F, 3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%qpop/f/str",of_QPOP_F_STR,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, { "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, From 886b6cd349e85097a6c0232b40a641b8ff5d3983 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 30 Aug 2014 09:45:09 -0700 Subject: [PATCH 05/13] Debug messages. --- elab_expr.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/elab_expr.cc b/elab_expr.cc index da4bf6c82..41ea2219f 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3359,6 +3359,12 @@ NetExpr* PEIdent::elaborate_expr_method_(Design*des, NetScope*scope, return 0; } + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr_method_: " + << "Give up trying to find method " << member_name + << " of " << path_ << "." << endl; + } + return 0; } From 1465fd1570afdd9afc7d289bffc2d54e136a1b2b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 2 Sep 2014 09:22:41 -0700 Subject: [PATCH 06/13] Class definitions may reference class types in containing scopes. We need the scope where the class is defined so that it can find types in that containing scope. Note that most definitions cannot escape into the the lexical scope of the class, but some can. --- elab_scope.cc | 1 + net_scope.cc | 7 +++++++ netclass.cc | 8 +++++++- netclass.h | 20 +++++++++++++++++++- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 87593c192..04cff8861 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -434,6 +434,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) class_scope->set_line(pclass); class_scope->set_class_def(use_class); use_class->set_class_scope(class_scope); + use_class->set_definition_scope(scope); // Collect the properties, elaborate them, and add them to the // elaborated class definition. diff --git a/net_scope.cc b/net_scope.cc index f7b4b925a..e20173ab9 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -654,6 +654,13 @@ netclass_t*NetScope::find_class(perm_string name) if (type_==MODULE) return 0; + if (up_==0 && type_==CLASS) { + assert(class_def_); + + NetScope*def_parent = class_def_->definition_scope(); + return def_parent->find_class(name); + } + // If there is no further to look, ... if (up_ == 0) return 0; diff --git a/netclass.cc b/netclass.cc index f302585d1..9c2d56c29 100644 --- a/netclass.cc +++ b/netclass.cc @@ -24,7 +24,7 @@ using namespace std; netclass_t::netclass_t(perm_string name, netclass_t*sup) -: name_(name), super_(sup), class_scope_(0) +: name_(name), super_(sup), class_scope_(0), definition_scope_(0) { } @@ -56,6 +56,12 @@ void netclass_t::set_class_scope(NetScope*class_scope) class_scope_ = class_scope; } +void netclass_t::set_definition_scope(NetScope*definition_scope) +{ + assert(definition_scope_ == 0); + definition_scope_ = definition_scope; +} + ivl_variable_type_t netclass_t::base_type() const { return IVL_VT_CLASS; diff --git a/netclass.h b/netclass.h index da7fb3e96..8679fa4f9 100644 --- a/netclass.h +++ b/netclass.h @@ -43,9 +43,19 @@ class netclass_t : public ivl_type_s { bool set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype); // Set the scope for the class. The scope has no parents and - // is used for the elaboration of methods (tasks/functions). + // is used for the elaboration of methods + // (tasks/functions). In other words, this is the class itself. void set_class_scope(NetScope*cscope); + // Set the scope for the class definition. This is the scope + // where the class definition was encountered, and may be used + // to locate symbols that the class definition may inherit + // from its context. This can be nil, or a package or module + // where a class is defined. + void set_definition_scope(NetScope*dscope); + + NetScope*definition_scope(void); + // As an ivl_type_s object, the netclass is always an // ivl_VT_CLASS object. ivl_variable_type_t base_type() const; @@ -115,6 +125,14 @@ class netclass_t : public ivl_type_s { // This holds task/function definitions for methods. NetScope*class_scope_; + + // This holds the context for the class type definition. + NetScope*definition_scope_; }; +inline NetScope*netclass_t::definition_scope(void) +{ + return definition_scope_; +} + #endif /* IVL_netclass_H */ From 3b0dfaadba004e15b0143d0ff7d9f1e5c7c5544c Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 2 Sep 2014 09:23:54 -0700 Subject: [PATCH 07/13] Some support for unpacked arrays in class properties. --- elab_lval.cc | 52 +++++++++++++++++++++++++++++++++++- elab_sig.cc | 44 +----------------------------- elab_type.cc | 19 ++++++++++--- elaborate.cc | 35 ++++++++++++++++++++++++ net_proc.cc | 2 +- netmisc.cc | 75 +++++++++++++++++++++++++++++++++++++++++++++++----- netmisc.h | 8 ++++++ netparray.cc | 22 ++++++++++----- netparray.h | 57 ++++++++++++++++++++++++++++++++------- 9 files changed, 245 insertions(+), 69 deletions(-) diff --git a/elab_lval.cc b/elab_lval.cc index f5ab1320e..84b283353 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -27,6 +27,7 @@ # include "netstruct.h" # include "netclass.h" # include "netdarray.h" +# include "netparray.h" # include "netvector.h" # include "compiler.h" # include @@ -259,6 +260,12 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, } ivl_assert(*this, reg); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lval: " + << "Lval reg = " << reg->name() << endl; + } + // We are processing the tail of a string of names. For // example, the verilog may be "a.b.c", so we are processing // "c" at this point. (Note that if method_name is not nil, @@ -389,7 +396,9 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, if (class_type == 0) return 0; - perm_string member_name = peek_tail_name(path_); + const name_component_t&name_comp = path_.back(); + + perm_string member_name = name_comp.name; int pidx = class_type->property_idx_from_name(member_name); if (pidx < 0) return 0; @@ -402,6 +411,46 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, return 0; } + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: " + << "Ident " << member_name + << " is a property of class " << class_type->get_name() << endl; + } + + NetExpr*canon_index = 0; + if (name_comp.index.size() > 0) { + ivl_type_t property_type = class_type->get_prop_type(pidx); + + if (const netsarray_t* stype = dynamic_cast (property_type)) { + list indices_const; + list indices_expr; + indices_flags flags; + indices_to_expressions(des, scope, this, + name_comp.index, name_comp.index.size(), + false, flags, + indices_expr, indices_const); + + if (flags.undefined) { + cerr << get_fileline() << ": warning: " + << "ignoring undefined l-value array access " + << member_name + << " (" << path_ << ")" + << "." << endl; + } else if (flags.variable) { + canon_index = normalize_variable_unpacked(*this, stype, indices_expr); + + } else { + canon_index = normalize_variable_unpacked(stype, indices_const); + } + + + } else { + cerr << get_fileline() << ": error: " + << "Index expressions don't apply to this type of property." << endl; + des->errors += 1; + } + } + // Detect assignment to constant properties. Note that the // initializer constructor MAY assign to constant properties, // as this is how the property gets its value. @@ -438,6 +487,7 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, NetAssign_*this_lval = new NetAssign_(this_net); this_lval->set_property(member_name); + if (canon_index) this_lval->set_word(canon_index); return this_lval; } diff --git a/elab_sig.cc b/elab_sig.cc index 37c10f0b8..9d5df8245 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -836,48 +836,6 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const statement_->elaborate_sig(des, scope); } -static bool evaluate_ranges(Design*des, NetScope*scope, - vector&llist, - const list&rlist) -{ - bool bad_msb = false, bad_lsb = false; - - for (list::const_iterator cur = rlist.begin() - ; cur != rlist.end() ; ++cur) { - long use_msb, use_lsb; - - NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); - if (! eval_as_long(use_msb, texpr)) { - cerr << cur->first->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << cur->first->get_fileline() << " : " - "This MSB expression violates the rule: " - << *cur->first << endl; - des->errors += 1; - bad_msb = true; - } - - delete texpr; - - texpr = elab_and_eval(des, scope, cur->second, -1, true); - if (! eval_as_long(use_lsb, texpr)) { - cerr << cur->second->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << cur->second->get_fileline() << " : " - "This LSB expression violates the rule: " - << *cur->second << endl; - des->errors += 1; - bad_lsb = true; - } - - delete texpr; - - llist.push_back(netrange_t(use_msb, use_lsb)); - } - - return bad_msb | bad_lsb; -} - static netclass_t* locate_class_type(Design*, NetScope*scope, class_type_t*class_type) { @@ -1288,7 +1246,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype - << " parray=" << use_type->packed_dimensions() + << " parray=" << use_type->static_dimensions() << " " << name_ << unpacked_dimensions << " in scope " << scope_path(scope) << endl; } diff --git a/elab_type.cc b/elab_type.cc index 1167c1902..2f3dab573 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -22,6 +22,7 @@ # include "netclass.h" # include "netdarray.h" # include "netenum.h" +# include "netparray.h" # include "netscalar.h" # include "netstruct.h" # include "netvector.h" @@ -203,9 +204,21 @@ ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const ivl_type_t btype = base_type->elaborate_type(des, scope); - assert(dims->size() == 1); + assert(dims->size() >= 1); list::const_iterator cur = dims->begin(); - assert(cur->first == 0 && cur->second==0); - ivl_type_s*res = new netdarray_t(btype); + + // Special case: if the dimension is nil:nil, this is a + // dynamic array. Note that we only know how to handle dynamic + // arrays with 1 dimension at a time. + if (cur->first==0 && cur->second==0) { + assert(dims->size()==1); + ivl_type_s*res = new netdarray_t(btype); + return res; + } + + vector dimensions; + bool bad_range = evaluate_ranges(des, scope, dimensions, *dims); + + ivl_type_s*res = new netuarray_t(dimensions, btype); return res; } diff --git a/elaborate.cc b/elaborate.cc index c8e801a5f..9050f7065 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -40,6 +40,7 @@ # include "netlist.h" # include "netvector.h" # include "netdarray.h" +# include "netparray.h" # include "netclass.h" # include "netmisc.h" # include "util.h" @@ -2290,6 +2291,14 @@ NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const NetAssign_*lv = new NetAssign_(tmp); return lv; } + + if (debug_elaborate) { + cerr << get_fileline() << ": PAssign_::elaborate_lval: " + << "lval_ = " << *lval_ << endl; + cerr << get_fileline() << ": PAssign_::elaborate_lval: " + << "lval_ expr type = " << typeid(*lval_).name() << endl; + } + return lval_->elaborate_lval(des, scope, false, false); } @@ -2520,6 +2529,22 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const rv = elaborate_rval_(des, scope, use_lv_type); + } else if (const netuarray_t*utype = dynamic_cast(lv_net_type)) { + ivl_assert(*this, lv->more==0); + if (debug_elaborate) { + if (lv->word()) + cerr << get_fileline() << ": PAssign::elaborate: " + << "lv->word() = " << *lv->word() << endl; + else + cerr << get_fileline() << ": PAssign::elaborate: " + << "lv->word() = " << endl; + } + ivl_type_t use_lv_type = lv_net_type; + ivl_assert(*this, lv->word()); + use_lv_type = utype->element_type(); + + rv = elaborate_rval_(des, scope, use_lv_type); + } else { /* Elaborate the r-value expression, then try to evaluate it. */ rv = elaborate_rval_(des, scope, lv_net_type, lv->expr_type(), count_lval_width(lv)); @@ -4595,6 +4620,16 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const pform_name_t array_name; array_name.push_back(name_component_t(array_var_)); NetNet*array_sig = des->find_signal(scope, array_name); + + if (array_sig == 0) { + cerr << get_fileline() << ": error:" + << " Unable to find " << array_name + << " in scope " << scope_path(scope) + << "." << endl; + des->errors += 1; + return 0; + } + ivl_assert(*this, array_sig); if (debug_elaborate) { diff --git a/net_proc.cc b/net_proc.cc index c10bff7ab..93c746b6d 100644 --- a/net_proc.cc +++ b/net_proc.cc @@ -139,7 +139,7 @@ void NetForLoop::wrap_up() NetBlock*internal_block = new NetBlock(NetBlock::SEQU, 0); internal_block->set_line(*this); - internal_block->append(statement_); + if (statement_) internal_block->append(statement_); internal_block->append(step_statement_); NetWhile*wloop = new NetWhile(condition_, internal_block); diff --git a/netmisc.cc b/netmisc.cc index e4928ad76..6c5409db9 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -22,6 +22,7 @@ # include # include # include "netlist.h" +# include "netparray.h" # include "netvector.h" # include "netmisc.h" # include "PExpr.h" @@ -526,10 +527,8 @@ static void make_strides(const vector&dims, * word. If any of the indices are out of bounds, return nil instead * of an expression. */ -NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) +static NetExpr* normalize_variable_unpacked(const vector&dims, list&indices) { - const vector&dims = net->unpacked_dims(); - // Make strides for each index. The stride is the distance (in // words) to the next element in the canonical array. vector stride (dims.size()); @@ -559,10 +558,20 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) return canonical_expr; } -NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) +NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) { const vector&dims = net->unpacked_dims(); + return normalize_variable_unpacked(dims, indices); +} +NetExpr* normalize_variable_unpacked(const netsarray_t*stype, list&indices) +{ + const vector&dims = stype->static_dimensions(); + return normalize_variable_unpacked(dims, indices); +} + +NetExpr* normalize_variable_unpacked(const LineInfo&loc, const vector&dims, list&indices) +{ // Make strides for each index. The stride is the distance (in // words) to the next element in the canonical array. vector stride (dims.size()); @@ -602,7 +611,7 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) if (use_stride != 1) min_wid += num_bits(use_stride); - tmp = pad_to_width(tmp, min_wid, *net); + tmp = pad_to_width(tmp, min_wid, loc); // Now generate the math to calculate the canonical address. NetExpr*tmp_scaled = 0; @@ -641,11 +650,23 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) // If we don't have an expression at this point, all the indices were // constant zero. But this variant of normalize_variable_unpacked() // is only used when at least one index is not a constant. - ivl_assert(*net, canonical_expr); + ivl_assert(loc, canonical_expr); return canonical_expr; } +NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) +{ + const vector&dims = net->unpacked_dims(); + return normalize_variable_unpacked(*net, dims, indices); +} + +NetExpr* normalize_variable_unpacked(const LineInfo&loc, const netsarray_t*stype, list&indices) +{ + const vector&dims = stype->static_dimensions(); + return normalize_variable_unpacked(loc, dims, indices); +} + NetEConst* make_const_x(unsigned long wid) { verinum xxx (verinum::Vx, wid); @@ -885,6 +906,48 @@ NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name, return tmp; } +bool evaluate_ranges(Design*des, NetScope*scope, + vector&llist, + const list&rlist) +{ + bool bad_msb = false, bad_lsb = false; + + for (list::const_iterator cur = rlist.begin() + ; cur != rlist.end() ; ++cur) { + long use_msb, use_lsb; + + NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); + if (! eval_as_long(use_msb, texpr)) { + cerr << cur->first->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->first->get_fileline() << " : " + "This MSB expression violates the rule: " + << *cur->first << endl; + des->errors += 1; + bad_msb = true; + } + + delete texpr; + + texpr = elab_and_eval(des, scope, cur->second, -1, true); + if (! eval_as_long(use_lsb, texpr)) { + cerr << cur->second->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->second->get_fileline() << " : " + "This LSB expression violates the rule: " + << *cur->second << endl; + des->errors += 1; + bad_lsb = true; + } + + delete texpr; + + llist.push_back(netrange_t(use_msb, use_lsb)); + } + + return bad_msb | bad_lsb; +} + void eval_expr(NetExpr*&expr, int context_width) { assert(expr); diff --git a/netmisc.h b/netmisc.h index 3e682fdd2..27583712b 100644 --- a/netmisc.h +++ b/netmisc.h @@ -21,6 +21,8 @@ # include "netlist.h" +class netsarray_t; + /* * Search for a symbol using the "start" scope as the starting * point. If the path includes a scope part, then locate the @@ -184,7 +186,10 @@ extern void indices_to_expressions(Design*des, NetScope*scope, list&indices,list&indices_const); extern NetExpr*normalize_variable_unpacked(const NetNet*net, list&indices); +extern NetExpr*normalize_variable_unpacked(const netsarray_t*net, list&indices); + extern NetExpr*normalize_variable_unpacked(const NetNet*net, list&indices); +extern NetExpr*normalize_variable_unpacked(const LineInfo&loc, const netsarray_t*net, list&indices); /* * This function takes as input a NetNet signal and adds a constant @@ -278,6 +283,9 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, unsigned lv_width, PExpr*expr, bool need_const =false); +extern bool evaluate_ranges(Design*des, NetScope*scope, + std::vector&llist, + const std::list&rlist); /* * This procedure evaluates an expression and if the evaluation is * successful the original expression is replaced with the new one. diff --git a/netparray.cc b/netparray.cc index 326b549fc..2adcac16e 100644 --- a/netparray.cc +++ b/netparray.cc @@ -22,6 +22,10 @@ using namespace std; +netsarray_t::~netsarray_t() +{ +} + netparray_t::~netparray_t() { } @@ -34,8 +38,8 @@ long netparray_t::packed_width(void) const { long cur_width = element_type()->packed_width(); - for (vector::const_iterator cur = packed_dims_.begin() - ; cur != packed_dims_.end() ; ++cur) { + for (vector::const_iterator cur = static_dimensions().begin() + ; cur != static_dimensions().end() ; ++cur) { cur_width *= cur->width(); } @@ -44,14 +48,20 @@ long netparray_t::packed_width(void) const vector netparray_t::slice_dimensions() const { + const vector&packed_dims = static_dimensions(); + vector elem_dims = element_type()->slice_dimensions(); - vector res (packed_dims_.size() + elem_dims.size()); + vector res (packed_dims.size() + elem_dims.size()); - for (size_t idx = 0 ; idx < packed_dims_.size() ; idx += 1) - res[idx] = packed_dims_[idx]; + for (size_t idx = 0 ; idx < packed_dims.size() ; idx += 1) + res[idx] = packed_dims[idx]; for (size_t idx = 0 ; idx < elem_dims.size() ; idx += 1) - res[idx+packed_dims_.size()] = elem_dims[idx]; + res[idx+packed_dims.size()] = elem_dims[idx]; return res; } + +netuarray_t::~netuarray_t() +{ +} diff --git a/netparray.h b/netparray.h index 96e8735af..2e0142a65 100644 --- a/netparray.h +++ b/netparray.h @@ -23,10 +23,39 @@ # include "nettypes.h" # include +/* + * Arrays with static dimensions (packed and unpacked) share this + * common base type. + */ +class netsarray_t : public netarray_t { + + public: + explicit netsarray_t(const std::vector&packed, + ivl_type_t etype); + ~netsarray_t(); + + public: + // Virtual methods from the ivl_type_s type... + + public: + inline const std::vector& static_dimensions() const + { return dims_; } + + private: + std::vector dims_; + +}; + +inline netsarray_t::netsarray_t(const std::vector&pd, + ivl_type_t etype) +: netarray_t(etype), dims_(pd) +{ +} + /* * Packed arrays. */ -class netparray_t : public netarray_t { +class netparray_t : public netsarray_t { public: explicit netparray_t(const std::vector&packed, @@ -38,18 +67,28 @@ class netparray_t : public netarray_t { long packed_width(void) const; std::vector slice_dimensions() const; - public: - inline const std::vector& packed_dimensions() const - { return packed_dims_; } - - private: - std::vector packed_dims_; - }; inline netparray_t::netparray_t(const std::vector&pd, ivl_type_t etype) -: netarray_t(etype), packed_dims_(pd) +: netsarray_t(pd, etype) +{ +} + +/* + * Unpacked arrays are very similar, but lack packed slices. + */ +class netuarray_t : public netsarray_t { + + public: + explicit netuarray_t(const std::vector&packed, + ivl_type_t etype); + ~netuarray_t(); +}; + +inline netuarray_t::netuarray_t(const std::vector&pd, + ivl_type_t etype) +: netsarray_t(pd, etype) { } From d1a35d51528f325923bff771a1086cd6e17fbe4e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 2 Sep 2014 12:19:58 -0700 Subject: [PATCH 08/13] Handle nil queue as a was to delete a queue. Treat this like assigning null to a dynamic array. This deletes the queue and thus has the effect of clearing it. --- PExpr.h | 4 ++++ elab_expr.cc | 18 ++++++++++++++++++ parse.y | 7 +++++-- tgt-vvp/stmt_assign.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/PExpr.h b/PExpr.h index 13aa0e22f..29945701a 100644 --- a/PExpr.h +++ b/PExpr.h @@ -245,6 +245,10 @@ class PEConcat : public PExpr { virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const; virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const; + + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + ivl_type_t type, unsigned flags) const; + virtual NetExpr*elaborate_expr(Design*des, NetScope*, unsigned expr_wid, unsigned flags) const; diff --git a/elab_expr.cc b/elab_expr.cc index 41ea2219f..638867133 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -2497,6 +2497,24 @@ unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&) // Keep track of the concatenation/repeat depth. static int concat_depth = 0; +NetExpr* PEConcat::elaborate_expr(Design*, NetScope*, + ivl_type_t type, unsigned /*flags*/) const +{ + switch (type->base_type()) { + case IVL_VT_QUEUE: + if (parms_.size() == 0) { + NetENull*tmp = new NetENull; + tmp->set_line(*this); + return tmp; + } + default: + cerr << get_fileline() << ": internal error: " + << "I don't know how to elaborate(ivl_type_t)" + << " this expression: " << *this << endl; + return 0; + } +} + NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const { diff --git a/parse.y b/parse.y index 42010d232..5701011a8 100644 --- a/parse.y +++ b/parse.y @@ -3456,11 +3456,14 @@ expr_primary | '{' '}' { // This is the empty queue syntax. if (gn_system_verilog()) { - yyerror(@1, "sorry: Expty queue expressions not supported."); + list empty_list; + PEConcat*tmp = new PEConcat(empty_list); + FILE_NAME(tmp, @1); + $$ = tmp; } else { yyerror(@1, "error: Concatenations are not allowed to be empty."); + $$ = 0; } - $$ = 0; } /* Cast expressions are primaries */ diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 74ffde30c..17d59694c 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -976,6 +976,30 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net) return errors; } +static int show_stmt_assign_sig_queue(ivl_statement_t net) +{ + int errors = 0; + ivl_lval_t lval = ivl_stmt_lval(net, 0); + ivl_expr_t rval = ivl_stmt_rval(net); + ivl_signal_t var= ivl_lval_sig(lval); + ivl_type_t var_type= ivl_signal_net_type(var); + assert(ivl_type_base(var_type) == IVL_VT_QUEUE); + + switch (ivl_expr_type(rval)) { + case IVL_EX_NULL: + errors += draw_eval_object(rval); + break; + default: + fprintf(stderr, "XXXX: I don't know how to handle expr_type=%d here\n", ivl_expr_type(rval)); + fprintf(vvp_out, " ; XXXX expr_type=%d\n", ivl_expr_type(rval)); + errors += 1; + break; + } + + fprintf(vvp_out, " %%store/obj v%p_0;\n", var); + return errors; +} + static int show_stmt_assign_sig_cobject(ivl_statement_t net) { int errors = 0; @@ -1106,6 +1130,10 @@ int show_stmt_assign(ivl_statement_t net) return show_stmt_assign_sig_darray(net); } + if (sig && (ivl_signal_data_type(sig) == IVL_VT_QUEUE)) { + return show_stmt_assign_sig_queue(net); + } + if (sig && (ivl_signal_data_type(sig) == IVL_VT_CLASS)) { return show_stmt_assign_sig_cobject(net); } From 15ccd8f4c9b589c4049b9cf4be50cc91f27497b6 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 4 Sep 2014 20:52:51 -0700 Subject: [PATCH 09/13] Handle foreach array name as class property. --- Statement.h | 2 +- elaborate.cc | 84 +++++++++++++++++++++++++++++++++++++++++++++++----- netclass.h | 3 +- 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/Statement.h b/Statement.h index 1785d9b6f..a9dcf1297 100644 --- a/Statement.h +++ b/Statement.h @@ -455,7 +455,7 @@ class PForeach : public Statement { private: NetProc* elaborate_static_array_(Design*des, NetScope*scope, - NetNet*array_sig) const; + const std::vector&dims) const; private: perm_string array_var_; diff --git a/elaborate.cc b/elaborate.cc index 9050f7065..281b2ecb9 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4605,6 +4605,27 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const return dev; } +static void find_property_in_class(const LineInfo&loc, const NetScope*scope, perm_string name, const netclass_t*&found_in, int&property) +{ + // Search up for the containing class. + while (scope && scope->type() != NetScope::CLASS) + scope = scope->parent(); + + found_in = 0; + property = -1; + + if (scope==0) return; + + found_in = scope->class_def(); + ivl_assert(loc, found_in); + + property = found_in->property_idx_from_name(name); + if (property < 0) { + found_in = 0; + return; + } +} + /* * The foreach statement can be written as a for statement like so: * @@ -4616,14 +4637,57 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const */ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const { - // Get the signal for the array variable + // Locate the signal for the array variable pform_name_t array_name; array_name.push_back(name_component_t(array_var_)); NetNet*array_sig = des->find_signal(scope, array_name); + // And if necessary, look for the class property that is + // referenced. + const netclass_t*class_scope = 0; + int class_property = -1; + if (array_sig == 0) + find_property_in_class(*this, scope, array_var_, class_scope, class_property); + + if (debug_elaborate && array_sig) { + cerr << get_fileline() << ": PForeach::elaborate: " + << "Found array_sig in " << scope_path(array_sig->scope()) << "." << endl; + } + + if (debug_elaborate && class_scope) { + cerr << get_fileline() << ": PForeach::elaborate: " + << "Found array_sig property (" << class_property + << ") in class " << class_scope->get_name() + << " as " << *class_scope->get_prop_type(class_property) << "." << endl; + } + + if (class_scope!=0 && class_property >= 0) { + ivl_type_t ptype = class_scope->get_prop_type(class_property); + const netsarray_t*atype = dynamic_cast (ptype); + if (atype == 0) { + cerr << get_fileline() << ": error: " + << "I can't handle the type of " << array_var_ + << " as a foreach loop." << endl; + des->errors += 1; + return 0; + } + + const std::vector&dims = atype->static_dimensions(); + if (dims.size() < index_vars_.size()) { + cerr << get_fileline() << ": error: " + << "class " << class_scope->get_name() + << " property " << array_var_ + << " has too few dimensions for foreach dimension list." << endl; + des->errors += 1; + return 0; + } + + return elaborate_static_array_(des, scope, dims); + } + if (array_sig == 0) { cerr << get_fileline() << ": error:" - << " Unable to find " << array_name + << " Unable to find foreach array " << array_name << " in scope " << scope_path(scope) << "." << endl; des->errors += 1; @@ -4643,11 +4707,15 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const // Classic arrays are processed this way. if (array_sig->data_type()==IVL_VT_BOOL) - return elaborate_static_array_(des, scope, array_sig); + return elaborate_static_array_(des, scope, array_sig->unpacked_dims()); if (array_sig->data_type()==IVL_VT_LOGIC) - return elaborate_static_array_(des, scope, array_sig); + return elaborate_static_array_(des, scope, array_sig->unpacked_dims()); if (array_sig->unpacked_dimensions() >= index_vars_.size()) - return elaborate_static_array_(des, scope, array_sig); + return elaborate_static_array_(des, scope, array_sig->unpacked_dims()); + + + // At this point, we know that the array is dynamic so we + // handle that slightly differently, using run-time tests. if (index_vars_.size() != 1) { cerr << get_fileline() << ": sorry: " @@ -4703,7 +4771,7 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const * and possibly do some optimizations. */ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, - NetNet*array_sig) const + const vector&dims) const { if (debug_elaborate) { cerr << get_fileline() << ": PForeach::elaborate_static_array_: " @@ -4711,13 +4779,13 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, } ivl_assert(*this, index_vars_.size() > 0); - ivl_assert(*this, array_sig->unpacked_dims().size() == index_vars_.size()); + ivl_assert(*this, dims.size() == index_vars_.size()); NetProc*sub = statement_->elaborate(des, scope); NetForLoop*stmt = 0; for (int idx_idx = index_vars_.size()-1 ; idx_idx >= 0 ; idx_idx -= 1) { - const netrange_t&idx_range = array_sig->unpacked_dims()[idx_idx]; + const netrange_t&idx_range = dims[idx_idx]; // Get the $high and $low constant values for this slice // of the array. diff --git a/netclass.h b/netclass.h index 8679fa4f9..8305da4ef 100644 --- a/netclass.h +++ b/netclass.h @@ -84,7 +84,8 @@ class netclass_t : public ivl_type_s { bool test_for_missing_initializers(void) const; - // Map the name of a property to its index. + // Map the name of a property to its index. Return <0 if the + // name is not a property in the class. int property_idx_from_name(perm_string pname) const; // The task method scopes from the method name. From 88e951418b578a0aa324cf9289c547a5ac76e5f6 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 6 Sep 2014 16:26:08 -0700 Subject: [PATCH 10/13] Handle elaboration of class properties referenced within sub-scopes. --- elab_expr.cc | 13 ++++++++++--- elab_lval.cc | 9 ++++++--- elaborate.cc | 11 ++--------- netmisc.cc | 33 +++++++++++++++++++++++++++++++++ netmisc.h | 7 +++++++ t-dll-expr.cc | 5 +++++ 6 files changed, 63 insertions(+), 15 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 638867133..d0eb01c2a 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3146,6 +3146,10 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, ivl_assert(*this, use_scope); } + if (NetExpr* tmp = elaborate_expr_class_member_(des, scope, 0, flags)) { + return tmp; + } + /* NetScope*found_in = */ symbol_search(this, des, use_scope, path_, net, par, eve, ex1, ex2); @@ -3289,7 +3293,7 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, if (path_.size() != 1) return 0; - const netclass_t*class_type = scope->parent()->class_def(); + const netclass_t*class_type = find_class_containing_scope(*this, scope); if (class_type == 0) return 0; @@ -3298,10 +3302,13 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, if (pidx < 0) return 0; - NetNet*this_net = scope->find_signal(perm_string::literal("@")); + NetScope*scope_method = find_method_containing_scope(*this, scope); + ivl_assert(*this, scope_method); + + NetNet*this_net = scope_method->find_signal(perm_string::literal("@")); if (this_net == 0) { cerr << get_fileline() << ": internal error: " - << "Unable to find 'this' port of " << scope_path(scope) + << "Unable to find 'this' port of " << scope_path(scope_method) << "." << endl; return 0; } diff --git a/elab_lval.cc b/elab_lval.cc index 84b283353..3888a3dbf 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -392,7 +392,7 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, if (path_.size() != 1) return 0; - const netclass_t*class_type = scope->parent()->class_def(); + const netclass_t*class_type = find_class_containing_scope(*this, scope); if (class_type == 0) return 0; @@ -403,10 +403,13 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, if (pidx < 0) return 0; - NetNet*this_net = scope->find_signal(perm_string::literal("@")); + NetScope*scope_method = find_method_containing_scope(*this, scope); + ivl_assert(*this, scope_method); + + NetNet*this_net = scope_method->find_signal(perm_string::literal("@")); if (this_net == 0) { cerr << get_fileline() << ": internal error: " - << "Unable to find 'this' port of " << scope_path(scope) + << "Unable to find 'this' port of " << scope_path(scope_method) << "." << endl; return 0; } diff --git a/elaborate.cc b/elaborate.cc index 281b2ecb9..ec5f0544e 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4607,17 +4607,10 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const static void find_property_in_class(const LineInfo&loc, const NetScope*scope, perm_string name, const netclass_t*&found_in, int&property) { - // Search up for the containing class. - while (scope && scope->type() != NetScope::CLASS) - scope = scope->parent(); - - found_in = 0; + found_in = find_class_containing_scope(loc, scope); property = -1; - if (scope==0) return; - - found_in = scope->class_def(); - ivl_assert(loc, found_in); + if (found_in==0) return; property = found_in->property_idx_from_name(name); if (property < 0) { diff --git a/netmisc.cc b/netmisc.cc index 6c5409db9..99dfa0bf5 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1496,3 +1496,36 @@ NetPartSelect* detect_partselect_lval(Link&pin) return found_ps; } + +const netclass_t* find_class_containing_scope(const LineInfo&loc, const NetScope*scope) +{ + while (scope && scope->type() != NetScope::CLASS) + scope = scope->parent(); + + if (scope == 0) + return 0; + + const netclass_t*found_in = scope->class_def(); + ivl_assert(loc, found_in); + return found_in; +} +/* + * Find the scope that contains this scope, that is the method for a + * class scope. Look for the scope whose PARENT is the scope for a + * class. This is going to be a method. + */ +NetScope* find_method_containing_scope(const LineInfo&, NetScope*scope) +{ + NetScope*up = scope->parent(); + + while (up && up->type() != NetScope::CLASS) { + scope = up; + up = up->parent(); + } + + if (up == 0) return 0; + + // Should I check if this scope is a TASK or FUNC? + + return scope; +} diff --git a/netmisc.h b/netmisc.h index 27583712b..e7ee8aad3 100644 --- a/netmisc.h +++ b/netmisc.h @@ -309,6 +309,13 @@ extern hname_t eval_path_component(Design*des, NetScope*scope, const name_component_t&comp, bool&error_flag); +/* + * If this scope is contained within a class scope (i.e. a method of a + * class) then return the class definition that contains it. + */ +extern const netclass_t*find_class_containing_scope(const LineInfo&loc,const NetScope*scope); +extern NetScope* find_method_containing_scope(const LineInfo&log, NetScope*scope); + /* * Return true if the data type is a type that is normally available * in vector for. IVL_VT_BOOL and IVL_VT_LOGIC are vectorable, diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 9b748d955..9974187b0 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -651,6 +651,11 @@ void dll_target::expr_ufunc(const NetEUFunc*net) FILE_NAME(expr, net); expr->u_.ufunc_.def = lookup_scope_(net->func()); + if (expr->u_.ufunc_.def == 0) { + cerr << net->get_fileline() << ": internal error: " + << "dll_target::expr_ufunc: " + << "Unable to match scope " << scope_path(net->func()) << endl; + } ivl_assert(*net, expr->u_.ufunc_.def); ivl_assert(*net, expr->u_.ufunc_.def->type_ == IVL_SCT_FUNCTION); From 8bb1d3dabe400f9a9710729a9b81665ccb25ca08 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 6 Sep 2014 17:39:52 -0700 Subject: [PATCH 11/13] Emit class definitions after ALL scopes are scanned. --- emit.cc | 16 ++++++++++++++-- netclass.h | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/emit.cc b/emit.cc index df661b909..c71e05c1e 100644 --- a/emit.cc +++ b/emit.cc @@ -409,14 +409,13 @@ void NetRepeat::emit_recurse(struct target_t*tgt) const void netclass_t::emit_scope(struct target_t*tgt) const { class_scope_->emit_scope(tgt); - class_scope_->emit_defs(tgt); } void NetScope::emit_scope(struct target_t*tgt) const { if (debug_emit) { cerr << "NetScope::emit_scope: " - << "Emit scope basename=" << basename() << endl; + << "Emit scope " << scope_path(this) << endl; } tgt->scope(this); @@ -461,12 +460,20 @@ bool NetScope::emit_defs(struct target_t*tgt) const { bool flag = true; + if (debug_emit) { + cerr << "NetScope::emit_defs: " + << "Emit definitions for " << scope_path(this) << endl; + } + switch (type_) { case PACKAGE: case MODULE: for (map::const_iterator cur = children_.begin() ; cur != children_.end() ; ++ cur ) flag &= cur->second->emit_defs(tgt); + for (map::const_iterator cur = classes_.begin() + ; cur != classes_.end() ; ++ cur) + flag &= cur->second->emit_defs(tgt); break; case FUNC: @@ -485,6 +492,11 @@ bool NetScope::emit_defs(struct target_t*tgt) const return flag; } +bool netclass_t::emit_defs(struct target_t*tgt) const +{ + return class_scope_->emit_defs(tgt); +} + int Design::emit(struct target_t*tgt) const { int rc = 0; diff --git a/netclass.h b/netclass.h index 8305da4ef..4b94293f9 100644 --- a/netclass.h +++ b/netclass.h @@ -105,6 +105,7 @@ class netclass_t : public ivl_type_s { void elaborate(Design*des, PClass*pclass); void emit_scope(struct target_t*tgt) const; + bool emit_defs(struct target_t*tgt) const; void dump_scope(ostream&fd) const; From facc982af49e063de548210c44258e6ef8712402 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 7 Sep 2014 16:22:49 -0700 Subject: [PATCH 12/13] Ability to compare arbitrary class-valued expression to nil. --- tgt-vvp/eval_expr.c | 12 +++++++++++- vvp/codes.h | 3 ++- vvp/compile.cc | 5 +++-- vvp/opcodes.txt | 4 ++++ vvp/vthread.cc | 11 ++++++++++- 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index d4028dddf..82c4bd428 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -527,7 +527,7 @@ static struct vector_info draw_binary_expr_eq_class(ivl_expr_t expr) ivl_expr_t word_ex = ivl_expr_oper1(le); int word_ix = allocate_word(); draw_eval_expr_into_integer(word_ex, word_ix); - fprintf(vvp_out, " %%test_nula v%p, %d;\n", sig, word_ix); + fprintf(vvp_out, " %%test_nul/a v%p, %d;\n", sig, word_ix); clr_word(word_ix); } fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base); @@ -536,6 +536,16 @@ static struct vector_info draw_binary_expr_eq_class(ivl_expr_t expr) return res; } + if (ivl_expr_type(re) == IVL_EX_NULL && ivl_expr_value(le)==IVL_VT_CLASS) { + draw_eval_object(le); + fprintf(vvp_out, " %%test_nul/obj;\n"); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base); + if (ivl_expr_opcode(expr) == 'n') + fprintf(vvp_out, " %%inv %u, 1;\n", res.base); + return res; + } + fprintf(stderr, "SORRY: Compare class handles not implemented\n"); fprintf(vvp_out, " ; XXXX compare class handles.\n"); vvp_errors += 1; diff --git a/vvp/codes.h b/vvp/codes.h index bbb555c7d..05e4af45d 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -219,7 +219,8 @@ extern bool of_SUBI(vthread_t thr, vvp_code_t code); extern bool of_SUBSTR(vthread_t thr, vvp_code_t code); extern bool of_SUBSTR_V(vthread_t thr, vvp_code_t code); extern bool of_TEST_NUL(vthread_t thr, vvp_code_t code); -extern bool of_TEST_NULA(vthread_t thr, vvp_code_t code); +extern bool of_TEST_NUL_A(vthread_t thr, vvp_code_t code); +extern bool of_TEST_NUL_OBJ(vthread_t thr, vvp_code_t code); extern bool of_VPI_CALL(vthread_t thr, vvp_code_t code); extern bool of_WAIT(vthread_t thr, vvp_code_t code); extern bool of_WAIT_FORK(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 0ab23b841..697c58064 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -265,8 +265,9 @@ static const struct opcode_table_s opcode_table[] = { { "%subi", of_SUBI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%substr", of_SUBSTR, 2,{OA_BIT1, OA_BIT2, OA_NONE} }, { "%substr/v",of_SUBSTR_V,3,{OA_BIT1, OA_BIT2, OA_NUMBER} }, - { "%test_nul", of_TEST_NUL, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, - { "%test_nula", of_TEST_NULA,2,{OA_ARR_PTR, OA_BIT1, OA_NONE} }, + { "%test_nul", of_TEST_NUL, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, + { "%test_nul/a", of_TEST_NUL_A, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} }, + { "%test_nul/obj",of_TEST_NUL_OBJ,0,{OA_NONE, OA_NONE, OA_NONE} }, { "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, { "%wait/fork",of_WAIT_FORK,0,{OA_NONE, OA_NONE, OA_NONE} }, { "%xnor", of_XNOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 6924f7f65..f3361f67b 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -1134,10 +1134,14 @@ values into the vector space. The string value is NOT popped. * %test_nul +* %test_nul/obj This instruction tests the contents of the addressed variable to see if it is null. If it is, set bit 4 to 1. Otherwise, set bit 4 to 0. +The %test_null/obj tests the object on the top of the stack, instead +of any variable. The value in the stack is NOT popped. + This is intended to implement the SystemVerilog expression (==null), where is a class variable. diff --git a/vvp/vthread.cc b/vvp/vthread.cc index db1d9e08a..ae2986364 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -5832,7 +5832,7 @@ bool of_TEST_NUL(vthread_t thr, vvp_code_t cp) return true; } -bool of_TEST_NULA(vthread_t thr, vvp_code_t cp) +bool of_TEST_NUL_A(vthread_t thr, vvp_code_t cp) { unsigned idx = cp->bit_idx[0]; unsigned adr = thr->words[idx].w_int; @@ -5853,6 +5853,15 @@ bool of_TEST_NULA(vthread_t thr, vvp_code_t cp) return true; } +bool of_TEST_NUL_OBJ(vthread_t thr, vvp_code_t) +{ + if (thr->peek_object().test_nil()) + thr_put_bit(thr, 4, BIT4_1); + else + thr_put_bit(thr, 4, BIT4_0); + return true; +} + bool of_VPI_CALL(vthread_t thr, vvp_code_t cp) { vpip_execute_vpi_call(thr, cp->handle); From 697701a26e1f75c428779e5b2f6979a0ab00f3c9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 7 Sep 2014 17:48:19 -0700 Subject: [PATCH 13/13] Sorry messages for property arrays. --- elab_expr.cc | 11 ++++++++++- elab_lval.cc | 7 +++++++ elab_scope.cc | 9 +++++---- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index d0eb01c2a..d27ad8adf 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -30,6 +30,7 @@ # include "netlist.h" # include "netclass.h" # include "netenum.h" +# include "netparray.h" # include "netvector.h" # include "discipline.h" # include "netmisc.h" @@ -3318,7 +3319,8 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, << "Found member " << member_name << " is a member of class " << class_type->get_name() << ", context scope=" << scope_path(scope) - << ", so synthesizing a NetEProperty." << endl; + << ", type=" << *class_type->get_prop_type(pidx) + << ", so making a NetEProperty." << endl; } property_qualifier_t qual = class_type->get_prop_qual(pidx); @@ -3334,6 +3336,13 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, return class_static_property_expression(this, class_type, member_name); } + ivl_type_t tmp_type = class_type->get_prop_type(pidx); + if (/* const netuarray_t*tmp_ua =*/ dynamic_cast(tmp_type)) { + cerr << get_fileline() << ": sorry: " + << "Unpacked array properties not supported yet." << endl; + des->errors += 1; + } + NetEProperty*tmp = new NetEProperty(this_net, member_name); tmp->set_line(*this); return tmp; diff --git a/elab_lval.cc b/elab_lval.cc index 3888a3dbf..6d647652c 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -488,6 +488,13 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, } } + ivl_type_t tmp_type = class_type->get_prop_type(pidx); + if (const netuarray_t*tmp_ua = dynamic_cast(tmp_type)) { + cerr << get_fileline() << ": sorry: " + << "Unpacked array properties (l-values) not supported yet." << endl; + des->errors += 1; + } + NetAssign_*this_lval = new NetAssign_(this_net); this_lval->set_property(member_name); if (canon_index) this_lval->set_word(canon_index); diff --git a/elab_scope.cc b/elab_scope.cc index 04cff8861..5c3db1c34 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -440,12 +440,13 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) // elaborated class definition. for (map::iterator cur = use_type->properties.begin() ; cur != use_type->properties.end() ; ++ cur) { - if (debug_scopes) { - cerr << pclass->get_fileline() << ": elaborate_scope_class: " - << " Property " << cur->first << endl; - } ivl_type_s*tmp = cur->second.type->elaborate_type(des, scope); ivl_assert(*pclass, tmp); + if (debug_scopes) { + cerr << pclass->get_fileline() << ": elaborate_scope_class: " + << " Property " << cur->first + << " type=" << *tmp << endl; + } use_class->set_property(cur->first, cur->second.qual, tmp); }