diff --git a/PExpr.cc b/PExpr.cc index 67f40bde5..9f20a33ca 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -426,6 +426,16 @@ PENewClass::PENewClass(void) { } +PENewClass::PENewClass(const list&p) +: parms_(p.size()) +{ + size_t tmp_idx = 0; + for (list::const_iterator cur = p.begin() + ; cur != p.end() ; ++ cur) { + parms_[tmp_idx++] = *cur; + } +} + PENewClass::~PENewClass() { } diff --git a/PExpr.h b/PExpr.h index 392ad2a01..69d1bc5fc 100644 --- a/PExpr.h +++ b/PExpr.h @@ -489,7 +489,9 @@ class PENewClass : public PExpr { public: explicit PENewClass (); + explicit PENewClass (const std::list&p); ~PENewClass(); + virtual void dump(ostream&) const; // Class objects don't have a useful width, but the expression // is IVL_VT_CLASS. @@ -502,6 +504,7 @@ class PENewClass : public PExpr { ivl_type_t type, unsigned flags) const; private: + std::vectorparms_; }; class PENull : public PExpr { diff --git a/elab_expr.cc b/elab_expr.cc index cf6ff341e..b3102573e 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -4448,12 +4448,82 @@ unsigned PENewClass::test_width(Design*, NetScope*, width_mode_t&) return 1; } -NetExpr* PENewClass::elaborate_expr(Design*, NetScope*, +NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope, ivl_type_t ntype, unsigned) const { - NetENew*tmp = new NetENew(ntype); - tmp->set_line(*this); - return tmp; + NetENew*obj = new NetENew(ntype); + obj->set_line(*this); + + // Find the constructor for the class. If there is no + // constructor then the result of this expression is the + // allocation alone. + const netclass_t*ctype = dynamic_cast (ntype); + NetScope*new_scope = ctype->method_from_name(perm_string::literal("new")); + if (new_scope == 0) { + // No constructor. + if (parms_.size() > 0) { + cerr << get_fileline() << ": error: " + << "Class " << ctype->get_name() + << " has no constructor, but you passed " << parms_.size() + << " arguments to the new operator." << endl; + des->errors += 1; + } + return obj; + } + + NetFuncDef*def = new_scope->func_def(); + ivl_assert(*this, def); + + if ((parms_.size()+1) != def->port_count()) { + cerr << get_fileline() << ": error: Parm count mismatch" + << " passing " << parms_.size() << " arguments " + << " to constructor expecting " << (def->port_count()-1) + << " arguments." << endl; + des->errors += 1; + return obj; + } + + vector parms (1 + parms_.size()); + parms[0] = obj; + + int missing_parms = 0; + int parm_errors = 0; + for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) { + PExpr*tmp = parms_[idx]; + size_t pidx = idx + 1; + + if (tmp == 0) { + parms[pidx] = 0; + missing_parms += 1; + continue; + } + + parms[pidx] = elaborate_rval_expr(des, scope, def->port(pidx)->data_type(), + def->port(pidx)->vector_width(), + tmp, false); + if (parms[pidx] == 0) { + parm_errors += 1; + continue; + } + } + + if (missing_parms > 0) { + cerr << get_fileline() << ": error: The " << scope_path(new_scope) + << " constructor call is missing arguments." << endl; + parm_errors += 1; + des->errors += 1; + } + + // The return value for the constructor is actually the "this" + // variable, instead of the "new" scope name. + NetNet*res = new_scope->find_signal(perm_string::literal("@")); + ivl_assert(*this, res); + + NetESignal*eres = new NetESignal(res); + NetEUFunc*con = new NetEUFunc(scope, new_scope, eres, parms, true); + con->set_line(*this); + + return con; } /* diff --git a/elab_sig.cc b/elab_sig.cc index fea0f837f..35e867426 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -537,20 +537,41 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const elaborate_sig_wires_(des, scope); - ivl_type_t ret_type; + NetNet*ret_sig; + if (gn_system_verilog() && fname == "new") { + // Special case: this is a constructor, so the return + // signal is also the first argument. For example, the + // source code for the definition may be: + // function new(...); + // endfunction + // In this case, the "@" port is the synthetic "this" + // argument and we also use it as a return value at the + // same time. + ret_sig = scope->find_signal(perm_string::literal("@")); + ivl_assert(*this, ret_sig); + + if (debug_elaborate) + cerr << get_fileline() << ": PFunction::elaborate_sig: " + << "Scope " << scope_path(scope) + << " is a CONSTRUCTOR, so use \"this\" argument" + << " as return value." << endl; - if (return_type_) { - ret_type = return_type_->elaborate_type(des, scope); } else { - netvector_t*tmp = new netvector_t(IVL_VT_LOGIC); - tmp->set_scalar(true); - ret_type = tmp; - } - list ret_unpacked; - NetNet*ret_sig = new NetNet(scope, fname, NetNet::REG, ret_unpacked, ret_type); + ivl_type_t ret_type; - ret_sig->set_line(*this); - ret_sig->port_type(NetNet::POUTPUT); + if (return_type_) { + ret_type = return_type_->elaborate_type(des, scope); + } else { + netvector_t*tmp = new netvector_t(IVL_VT_LOGIC); + tmp->set_scalar(true); + ret_type = tmp; + } + list ret_unpacked; + ret_sig = new NetNet(scope, fname, NetNet::REG, ret_unpacked, ret_type); + + ret_sig->set_line(*this); + ret_sig->port_type(NetNet::POUTPUT); + } vectorports; elaborate_sig_ports_(des, scope, ports); diff --git a/parse.y b/parse.y index ff2700f10..1cb8c8bf0 100644 --- a/parse.y +++ b/parse.y @@ -844,8 +844,10 @@ class_new /* IEEE1800-2005 A.2.4 */ $$ = tmp; } | K_new '(' expression_list_proper ')' - { yyerror(@1, "sorry: class_new not implemented yet."); - $$ = 0; + { PENewClass*tmp = new PENewClass(*$3); + FILE_NAME(tmp, @1); + delete $3; + $$ = tmp; } | K_new { PENewClass*tmp = new PENewClass; diff --git a/pform_dump.cc b/pform_dump.cc index eaca892a5..2e3eabfb5 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -291,7 +291,15 @@ void PENew::dump(ostream&out) const void PENewClass::dump(ostream&out) const { - out << "class_new"; + out << "class_new("; + if (parms_.size() > 0) { + parms_[0]->dump(out); + for (size_t idx = 1 ; idx < parms_.size() ; idx += 1) { + out << ", "; + parms_[idx]->dump(out); + } + } + out << ")"; } void PENull::dump(ostream&out) const @@ -874,17 +882,17 @@ void PForStatement::dump(ostream&out, unsigned ind) const void PFunction::dump(ostream&out, unsigned ind) const { out << setw(ind) << "" << "function "; - if (is_auto_) out << "automatic..."; + if (is_auto_) out << "automatic "; + + out << pscope_name() << ";" << endl; + if (method_of()) + out << setw(ind) << "" << "method of " << method_of()->name << ";" << endl; if (return_type_) return_type_->pform_dump(out, ind+8); else out << setw(ind+8) << "" << "" << endl; - out << pscope_name() << ";" << endl; - if (method_of()) - out << setw(ind) << "" << "method of " << method_of()->name << ";" << endl; - dump_ports_(out, ind); dump_parameters_(out, ind); diff --git a/tgt-vvp/draw_ufunc.c b/tgt-vvp/draw_ufunc.c index 3755158bb..83f4d2137 100644 --- a/tgt-vvp/draw_ufunc.c +++ b/tgt-vvp/draw_ufunc.c @@ -88,25 +88,10 @@ static void draw_function_argument(ivl_signal_t port, ivl_expr_t expr) } } -/* - * A call to a user defined function generates a result that is the - * result of this expression. - * - * The result of the function is placed by the function execution into - * a signal within the scope of the function that also has a basename - * the same as the function. The ivl_target API handled the result - * mapping already, and we get the name of the result signal as - * parameter 0 of the function definition. - */ - -struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid) +static void draw_ufunc_preamble(ivl_expr_t expr) { - unsigned idx; - unsigned swid = ivl_expr_width(expr); ivl_scope_t def = ivl_expr_def(expr); - ivl_signal_t retval = ivl_scope_port(def, 0); - struct vector_info res; - unsigned load_wid; + unsigned idx; /* If this is an automatic function, allocate the local storage. */ if (ivl_scope_is_auto(def)) { @@ -122,12 +107,45 @@ struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid) draw_function_argument(port, ivl_expr_parm(expr, idx)); } - /* Call the function */ fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); fprintf(vvp_out, " %%join;\n"); +} + +static void draw_ufunc_epilogue(ivl_expr_t expr) +{ + ivl_scope_t def = ivl_expr_def(expr); + + /* If this is an automatic function, free the local storage. */ + if (ivl_scope_is_auto(def)) { + fprintf(vvp_out, " %%free S_%p;\n", def); + } +} + +/* + * A call to a user defined function generates a result that is the + * result of this expression. + * + * The result of the function is placed by the function execution into + * a signal within the scope of the function that also has a basename + * the same as the function. The ivl_target API handled the result + * mapping already, and we get the name of the result signal as + * parameter 0 of the function definition. + */ + +struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid) +{ + unsigned swid = ivl_expr_width(expr); + ivl_scope_t def = ivl_expr_def(expr); + ivl_signal_t retval = ivl_scope_port(def, 0); + struct vector_info res; + unsigned load_wid; + + /* Take in arguments to function and call function code. */ + draw_ufunc_preamble(expr); + /* Fresh basic block starts after the join. */ clear_expression_lookaside(); @@ -159,11 +177,7 @@ struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid) if (load_wid < wid) pad_expr_in_place(expr, res, swid); - /* If this is an automatic function, free the local storage. */ - if (ivl_scope_is_auto(def)) { - fprintf(vvp_out, " %%free S_%p;\n", def); - } - + draw_ufunc_epilogue(expr); return res; } @@ -171,24 +185,9 @@ void draw_ufunc_real(ivl_expr_t expr) { ivl_scope_t def = ivl_expr_def(expr); ivl_signal_t retval = ivl_scope_port(def, 0); - unsigned idx; - /* If this is an automatic function, allocate the local storage. */ - if (ivl_scope_is_auto(def)) { - fprintf(vvp_out, " %%alloc S_%p;\n", def); - } - - assert(ivl_expr_parms(expr) == (ivl_scope_ports(def)-1)); - for (idx = 0 ; idx < ivl_expr_parms(expr) ; idx += 1) { - ivl_signal_t port = ivl_scope_port(def, idx+1); - draw_function_argument(port, ivl_expr_parm(expr, idx)); - } - - - /* Call the function */ - fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def))); - fprintf(vvp_out, ", S_%p;\n", def); - fprintf(vvp_out, " %%join;\n"); + /* Take in arguments to function and call the function code. */ + draw_ufunc_preamble(expr); /* Return value signal cannot be an array. */ assert(ivl_signal_dimensions(retval) == 0); @@ -196,9 +195,20 @@ void draw_ufunc_real(ivl_expr_t expr) /* Load the result into a word. */ fprintf(vvp_out, " %%load/real v%p_0;\n", retval); - /* If this is an automatic function, free the local storage. */ - if (ivl_scope_is_auto(def)) { - fprintf(vvp_out, " %%free S_%p;\n", def); - } + draw_ufunc_epilogue(expr); } + +void draw_ufunc_object(ivl_expr_t expr) +{ + ivl_scope_t def = ivl_expr_def(expr); + ivl_signal_t retval = ivl_scope_port(def, 0); + + /* Take in arguments to function and call the function code. */ + draw_ufunc_preamble(expr); + + /* Load the result into the object stack. */ + fprintf(vvp_out, " %%load/obj v%p_0;\n", retval); + + draw_ufunc_epilogue(expr); +} diff --git a/tgt-vvp/eval_object.c b/tgt-vvp/eval_object.c index e50f0af16..02c7dbe63 100644 --- a/tgt-vvp/eval_object.c +++ b/tgt-vvp/eval_object.c @@ -97,6 +97,12 @@ static int eval_object_signal(ivl_expr_t ex) return 0; } +static int eval_object_ufunc(ivl_expr_t ex) +{ + draw_ufunc_object(ex); + return 0; +} + int draw_eval_object(ivl_expr_t ex) { switch (ivl_expr_type(ex)) { @@ -122,6 +128,9 @@ int draw_eval_object(ivl_expr_t ex) case IVL_EX_SIGNAL: return eval_object_signal(ex); + case IVL_EX_UFUNC: + return eval_object_ufunc(ex); + default: fprintf(vvp_out, "; ERROR: draw_eval_object: Invalid expression type %u\n", ivl_expr_type(ex)); return 1; diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 3c4800fe2..e94a2364b 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -101,6 +101,7 @@ extern void draw_lpm_mux(ivl_lpm_t net); extern struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid); extern void draw_ufunc_real(ivl_expr_t expr); +extern void draw_ufunc_object(ivl_expr_t expr); extern void pad_expr_in_place(ivl_expr_t expr, struct vector_info res, unsigned swid);