From 16414f921fc2c3e7b1636ccad0a1d0075c3b6350 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 14 Sep 2013 19:54:35 -0700 Subject: [PATCH] Handle default arguments in class new functions. --- PTask.h | 7 ++++++- elab_expr.cc | 44 ++++++++++++++++++++++++++++++-------------- elab_sig.cc | 34 ++++++++++++++++++++++++---------- netlist.cc | 21 +++++++++++++++++---- netlist.h | 12 +++++++++--- 5 files changed, 86 insertions(+), 32 deletions(-) diff --git a/PTask.h b/PTask.h index 51877f1d5..69c0723e6 100644 --- a/PTask.h +++ b/PTask.h @@ -26,6 +26,7 @@ # include # include class Design; +class NetExpr; class NetNet; class NetScope; class PWire; @@ -48,8 +49,12 @@ class PTaskFunc : public PScope, public LineInfo { inline class_type_t* method_of() const { return this_type_; } protected: + // Elaborate the ports list. Write into the ports vector the + // NetNet pointers for the ports, and write into the pdefs the + // default value expressions, if any. void elaborate_sig_ports_(Design*des, NetScope*scope, - std::vector&ports) const; + std::vector&ports, + std::vector&pdefs) const; void dump_ports_(std::ostream&out, unsigned ind) const; diff --git a/elab_expr.cc b/elab_expr.cc index 233f72c00..588766ce6 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -4586,37 +4586,53 @@ NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope, NetFuncDef*def = new_scope->func_def(); ivl_assert(*this, def); - if ((parms_.size()+1) != def->port_count()) { + // Are there too many arguments passed to the function. If so, + // generate an error message. The case of too few arguments + // will be handled below, when we run out of arguments. + 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()); + vector parms (def->port_count()); 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; + for (size_t idx = 1 ; idx < parms.size() ; idx += 1) { + // While there are default arguments, check them. + if (idx <= parms_.size()) { + PExpr*tmp = parms_[idx-1]; + if (tmp == 0) { + parms[idx] = 0; + missing_parms += 1; + continue; + } + + parms[idx] = elaborate_rval_expr(des, scope, def->port(idx)->data_type(), + def->port(idx)->vector_width(), + tmp, false); + if (parms[idx] == 0) + parm_errors += 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; + // Ran out of explicit arguments. Is there a default + // argument we can use? + if (NetExpr*tmp = def->port_defe(idx)) { + parms[idx] = tmp; continue; } + + // If we run out of passed expressions, and there is no + // default value for this port, then we will need to + // report an error that we are missing parameters. + missing_parms += 1; + parms[idx] = 0; } if (missing_parms > 0) { diff --git a/elab_sig.cc b/elab_sig.cc index 9596fdf86..5e9058eb6 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -596,10 +596,11 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const } vectorports; - elaborate_sig_ports_(des, scope, ports); + vectorpdef; + elaborate_sig_ports_(des, scope, ports, pdef); NetFuncDef*def = 0; - if (ret_sig) def = new NetFuncDef(scope, ret_sig, ports); + if (ret_sig) def = new NetFuncDef(scope, ret_sig, ports, pdef); assert(def); if (debug_elaborate) @@ -630,8 +631,9 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const elaborate_sig_wires_(des, scope); vectorports; - elaborate_sig_ports_(des, scope, ports); - NetTaskDef*def = new NetTaskDef(scope, ports); + vectorpdefs; + elaborate_sig_ports_(des, scope, ports, pdefs); + NetTaskDef*def = new NetTaskDef(scope, ports, pdefs); scope->set_task_def(def); // Look for further signals in the sub-statement @@ -640,10 +642,11 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const } void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope, - vector&ports) const + vector&ports, vector&pdefs) const { if (ports_ == 0) { ports.clear(); + pdefs.clear(); /* Make sure the function has at least one input port. If it fails this test, print an error @@ -661,13 +664,16 @@ void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope, } ports.resize(ports_->size()); + pdefs.resize(ports_->size()); for (size_t idx = 0 ; idx < ports_->size() ; idx += 1) { perm_string port_name = ports_->at(idx).port->basename(); ports[idx] = 0; + pdefs[idx] = 0; NetNet*tmp = scope->find_signal(port_name); + NetExpr*tmp_def = 0; if (tmp == 0) { cerr << get_fileline() << ": internal error: " << "task/function " << scope_path(scope) @@ -678,11 +684,18 @@ void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope, continue; } + // If the port has a default expression that can be used + // as a value when the caller doesn't bind, then + // elaborate that expression here. This expression + // should evaluate down do a constant. if (ports_->at(idx).defe != 0) { - cerr << get_fileline() << ": sorry: " - << "task/function default port expressions not supported." - << endl; - des->errors += 1; + tmp_def = elab_and_eval(des, scope, ports_->at(idx).defe, -1, true); + if (tmp_def==0) { + cerr << get_fileline() << ": error: Unable to evaluate " + << *ports_->at(idx).defe + << " as a port default (constant) expression." << endl; + des->errors += 1; + } } if (tmp->port_type() == NetNet::NOT_A_PORT) { @@ -696,11 +709,12 @@ void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope, } ports[idx] = tmp; + pdefs[idx] = tmp_def; if (scope->type()==NetScope::FUNC && tmp->port_type()!=NetNet::PINPUT) { cerr << tmp->get_fileline() << ": error: " << "Function " << scope_path(scope) << " port " << port_name - << " is not an inputport." << endl; + << " is not an input port." << endl; cerr << tmp->get_fileline() << ": : " << "Function arguments must be input ports." << endl; des->errors += 1; diff --git a/netlist.cc b/netlist.cc index e3f876c88..d3066a50e 100644 --- a/netlist.cc +++ b/netlist.cc @@ -2043,8 +2043,9 @@ verinum::V NetConst::value(unsigned idx) const return value_[idx]; } -NetFuncDef::NetFuncDef(NetScope*s, NetNet*result, const vector&po) -: scope_(s), statement_(0), result_sig_(result), ports_(po) +NetFuncDef::NetFuncDef(NetScope*s, NetNet*result, const vector&po, + const vector&pd) +: scope_(s), statement_(0), result_sig_(result), ports_(po), pdefaults_(pd) { } @@ -2085,6 +2086,12 @@ const NetNet* NetFuncDef::port(unsigned idx) const return ports_[idx]; } +NetExpr* NetFuncDef::port_defe(unsigned idx) const +{ + assert(idx < pdefaults_.size()); + return pdefaults_[idx]; +} + const NetNet* NetFuncDef::return_sig() const { return result_sig_; @@ -2620,8 +2627,8 @@ unsigned NetUReduce::width() const return width_; } -NetTaskDef::NetTaskDef(NetScope*n, const vector&po) -: scope_(n), proc_(0), ports_(po) +NetTaskDef::NetTaskDef(NetScope*n, const vector&po, const vector&pd) +: scope_(n), proc_(0), ports_(po), pdefaults_(pd) { } @@ -2647,6 +2654,12 @@ NetNet* NetTaskDef::port(unsigned idx) const return ports_[idx]; } +NetExpr* NetTaskDef::port_defe(unsigned idx) const +{ + assert(idx < pdefaults_.size()); + return pdefaults_[idx]; +} + const NetScope* NetTaskDef::scope() const { return scope_; diff --git a/netlist.h b/netlist.h index e945d7fca..d2cbc15d0 100644 --- a/netlist.h +++ b/netlist.h @@ -3215,7 +3215,8 @@ class NetFree : public NetProc { class NetFuncDef { public: - NetFuncDef(NetScope*, NetNet*result, const std::vector&po); + NetFuncDef(NetScope*, NetNet*result, const std::vector&po, + const std::vector&pd); ~NetFuncDef(); void set_proc(NetProc*st); @@ -3227,6 +3228,7 @@ class NetFuncDef { unsigned port_count() const; const NetNet*port(unsigned idx) const; + NetExpr*port_defe(unsigned idx) const; const NetNet*return_sig() const; @@ -3243,6 +3245,7 @@ class NetFuncDef { NetProc*statement_; NetNet*result_sig_; std::vectorports_; + std::vectorpdefaults_; }; /* @@ -3375,7 +3378,8 @@ class NetSTask : public NetProc { class NetTaskDef { public: - NetTaskDef(NetScope*n, const vector&po); + NetTaskDef(NetScope*n, const vector&po, + const std::vector&pd); ~NetTaskDef(); void set_proc(NetProc*p); @@ -3386,6 +3390,7 @@ class NetTaskDef { unsigned port_count() const; NetNet*port(unsigned idx) const; + NetExpr*port_defe(unsigned idx) const; void dump(ostream&, unsigned) const; DelayType delay_type() const; @@ -3393,7 +3398,8 @@ class NetTaskDef { private: NetScope*scope_; NetProc*proc_; - vectorports_; + std::vectorports_; + std::vectorpdefaults_; // Default expressions for ports. private: // not implemented NetTaskDef(const NetTaskDef&);