diff --git a/PTask.h b/PTask.h index 69d964878..8b07ea897 100644 --- a/PTask.h +++ b/PTask.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: PTask.h,v 1.4 1999/08/25 22:22:41 steve Exp $" +#ident "$Id: PTask.h,v 1.5 1999/09/01 20:46:19 steve Exp $" #endif # include "LineInfo.h" @@ -63,7 +63,10 @@ class PFunction : public LineInfo { void set_output(PWire*); - virtual void elaborate(Design *des, const string &path) const; + /* Functions are elaborated in 2 passes. */ + virtual void elaborate_1(Design *des, const string &path) const; + virtual void elaborate_2(Design *des, const string &path) const; + void dump(ostream&, unsigned) const; private: @@ -74,6 +77,11 @@ class PFunction : public LineInfo { /* * $Log: PTask.h,v $ + * Revision 1.5 1999/09/01 20:46:19 steve + * Handle recursive functions and arbitrary function + * references to other functions, properly pass + * function parameters and save function results. + * * Revision 1.4 1999/08/25 22:22:41 steve * elaborate some aspects of functions. * diff --git a/design_dump.cc b/design_dump.cc index a0bdedb5b..296619379 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: design_dump.cc,v 1.36 1999/08/31 22:38:29 steve Exp $" +#ident "$Id: design_dump.cc,v 1.37 1999/09/01 20:46:19 steve Exp $" #endif /* @@ -427,7 +427,10 @@ void NetForever::dump(ostream&o, unsigned ind) const void NetFuncDef::dump(ostream&o, unsigned ind) const { o << setw(ind) << "" << "function " << name_ << endl; - statement_->dump(o, ind+2); + if (statement_) + statement_->dump(o, ind+2); + else + o << setw(ind+2) << "" << "// NO STATEMENT" << endl; } void NetPDelay::dump(ostream&o, unsigned ind) const @@ -719,6 +722,11 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.37 1999/09/01 20:46:19 steve + * Handle recursive functions and arbitrary function + * references to other functions, properly pass + * function parameters and save function results. + * * Revision 1.36 1999/08/31 22:38:29 steve * Elaborate and emit to vvm procedural functions. * diff --git a/elaborate.cc b/elaborate.cc index c9609794c..cf0c433e5 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: elaborate.cc,v 1.74 1999/08/31 22:38:29 steve Exp $" +#ident "$Id: elaborate.cc,v 1.75 1999/09/01 20:46:19 steve Exp $" #endif /* @@ -736,7 +736,13 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path, NetEUFunc* PECallFunction::elaborate_expr(Design*des, const string&path) const { string myname = path+"."+name_; - NetFuncDef*def = des->find_function(myname); + NetFuncDef*def = des->find_function(path, name_); + if (def == 0) { + cerr << get_line() << ": No function " << name_ << + " in this context (" << path << ")." << endl; + des->errors += 1; + return 0; + } assert(def); svector parms (parms_.count()); @@ -745,7 +751,17 @@ NetEUFunc* PECallFunction::elaborate_expr(Design*des, const string&path) const parms[idx] = tmp; } - NetNet*res = des->find_signal(myname, name_); + /* Look for the return value signal for the called function in + the context of the function definition, not my context. */ + NetNet*res = des->find_signal(def->name(), name_); + if (res == 0) { + cerr << get_line() << ": INTERNAL ERROR: Unable to locate " + "function return value for " << name_ << " in " << + def->name() << "." << endl; + des->errors += 1; + return 0; + } + assert(res); NetESignal*eres = new NetESignal(res); assert(eres); @@ -1887,16 +1903,16 @@ NetProc* PForStatement::elaborate(Design*des, const string&path) const return top; } -void PFunction::elaborate(Design*des, const string&path) const +/* + * Elaborating function definitions takes 2 passes. The first creates + * the NetFuncDef object and attaches the ports to it. The second pass + * (elaborate_2) elaborates the statement that is contained + * within. These passes are needed because the statement may invoke + * the function itself (or other functions) so can't be elaborated + * until all the functions are partially elaborated. + */ +void PFunction::elaborate_1(Design*des, const string&path) const { - NetProc*st = statement_->elaborate(des, path); - if (st == 0) { - cerr << statement_->get_line() << ": Unable to elaborate " - "statement in function " << path << " at " << get_line() - << "." << endl; - return; - } - /* Translate the wires that are ports to NetNet pointers by presuming that the name is already elaborated, and look it up in the design. Then save that pointer for later use by @@ -1910,11 +1926,26 @@ void PFunction::elaborate(Design*des, const string&path) const ports[idx+1] = tmp; } - - NetFuncDef*def = new NetFuncDef(path, st, ports); + NetFuncDef*def = new NetFuncDef(path, ports); des->add_function(path, def); } +void PFunction::elaborate_2(Design*des, const string&path) const +{ + NetFuncDef*def = des->find_function(path); + assert(def); + + NetProc*st = statement_->elaborate(des, path); + if (st == 0) { + cerr << statement_->get_line() << ": Unable to elaborate " + "statement in function " << path << "." << endl; + des->errors += 1; + return; + } + + def->set_proc(st); +} + NetProc* PRepeat::elaborate(Design*des, const string&path) const { NetExpr*expr = expr_->elaborate_expr(des, path); @@ -2036,10 +2067,17 @@ bool Module::elaborate(Design*des, const string&path, svector*overrides_ // Elaborate functions. typedef map::const_iterator mfunc_it_t; + for (mfunc_it_t cur = funcs_.begin() ; cur != funcs_.end() ; cur ++) { string pname = path + "." + (*cur).first; - (*cur).second->elaborate(des, pname); + (*cur).second->elaborate_1(des, pname); + } + + for (mfunc_it_t cur = funcs_.begin() + ; cur != funcs_.end() ; cur ++) { + string pname = path + "." + (*cur).first; + (*cur).second->elaborate_2(des, pname); } // Elaborate the task definitions. This is done before the @@ -2127,6 +2165,11 @@ Design* elaborate(const map&modules, /* * $Log: elaborate.cc,v $ + * Revision 1.75 1999/09/01 20:46:19 steve + * Handle recursive functions and arbitrary function + * references to other functions, properly pass + * function parameters and save function results. + * * Revision 1.74 1999/08/31 22:38:29 steve * Elaborate and emit to vvm procedural functions. * diff --git a/netlist.cc b/netlist.cc index ec6beb639..c29f4aa2f 100644 --- a/netlist.cc +++ b/netlist.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.cc,v 1.54 1999/08/31 22:38:29 steve Exp $" +#ident "$Id: netlist.cc,v 1.55 1999/09/01 20:46:19 steve Exp $" #endif # include @@ -482,8 +482,8 @@ NetProc* NetCondit::else_clause() return else_; } -NetFuncDef::NetFuncDef(const string&n, NetProc*st, const svector&po) -: name_(n), statement_(st), ports_(po) +NetFuncDef::NetFuncDef(const string&n, const svector&po) +: name_(n), statement_(0), ports_(po) { } @@ -496,11 +496,29 @@ const string& NetFuncDef::name() const return name_; } +void NetFuncDef::set_proc(NetProc*st) +{ + assert(statement_ == 0); + assert(st != 0); + statement_ = st; +} + const NetProc* NetFuncDef::proc() const { return statement_; } +unsigned NetFuncDef::port_count() const +{ + return ports_.count(); +} + +const NetNet* NetFuncDef::port(unsigned idx) const +{ + assert(idx < ports_.count()); + return ports_[idx]; +} + NetNEvent::NetNEvent(const string&ev, unsigned wid, Type e, NetPEvent*pe) : NetNode(ev, wid), sref(pe), edge_(e) { @@ -560,6 +578,7 @@ const NetExpr* NetSTask::parm(unsigned idx) const NetEUFunc::NetEUFunc(NetFuncDef*def, NetESignal*res, svector&p) : func_(def), result_(res), parms_(p) { + expr_width(result_->expr_width()); } NetEUFunc::~NetEUFunc() @@ -578,6 +597,22 @@ const NetESignal*NetEUFunc::result() const return result_; } +unsigned NetEUFunc::parm_count() const +{ + return parms_.count(); +} + +const NetExpr* NetEUFunc::parm(unsigned idx) const +{ + assert(idx < parms_.count()); + return parms_[idx]; +} + +const NetFuncDef* NetEUFunc::definition() const +{ + return func_; +} + /* * XXXX FIX ME: For now, just take whatever the caller says as my * width. What I really need to do is note the width of the output @@ -1501,13 +1536,31 @@ void Design::add_function(const string&key, NetFuncDef*def) funcs_[key] = def; } +NetFuncDef* Design::find_function(const string&path, const string&name) +{ + string root = path; + for (;;) { + string key = root + "." + name; + map::const_iterator cur = funcs_.find(key); + if (cur != funcs_.end()) + return (*cur).second; + + unsigned pos = root.rfind('.'); + if (pos > root.length()) + break; + + root = root.substr(0, pos); + } + + return 0; +} + NetFuncDef* Design::find_function(const string&key) { map::const_iterator cur = funcs_.find(key); - if (cur == funcs_.end()) - return 0; - - return (*cur).second; + if (cur != funcs_.end()) + return (*cur).second; + return 0; } void Design::add_task(const string&key, NetTaskDef*def) @@ -1642,6 +1695,11 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*)) /* * $Log: netlist.cc,v $ + * Revision 1.55 1999/09/01 20:46:19 steve + * Handle recursive functions and arbitrary function + * references to other functions, properly pass + * function parameters and save function results. + * * Revision 1.54 1999/08/31 22:38:29 steve * Elaborate and emit to vvm procedural functions. * diff --git a/netlist.h b/netlist.h index 10e44ba37..abbeabf9b 100644 --- a/netlist.h +++ b/netlist.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.h,v 1.58 1999/08/31 22:38:29 steve Exp $" +#ident "$Id: netlist.h,v 1.59 1999/09/01 20:46:19 steve Exp $" #endif /* @@ -768,12 +768,17 @@ class NetForever : public NetProc { class NetFuncDef { public: - NetFuncDef(const string&, NetProc*st, const svector&po); + NetFuncDef(const string&, const svector&po); ~NetFuncDef(); + void set_proc(NetProc*st); + const string& name() const; const NetProc*proc() const; + unsigned port_count() const; + const NetNet*port(unsigned idx) const; + virtual void dump(ostream&, unsigned ind) const; private: @@ -951,6 +956,10 @@ class NetEUFunc : public NetExpr { const string& name() const; const NetESignal*result() const; + unsigned parm_count() const; + const NetExpr* parm(unsigned idx) const; + + const NetFuncDef* definition() const; virtual bool set_width(unsigned); virtual void dump(ostream&) const; @@ -1402,7 +1411,8 @@ class Design { // Functions void add_function(const string&n, NetFuncDef*); - NetFuncDef* find_function(const string&key); + NetFuncDef* find_function(const string&path, const string&key); + NetFuncDef* find_function(const string&path); // Tasks void add_task(const string&n, NetTaskDef*); @@ -1508,6 +1518,11 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.59 1999/09/01 20:46:19 steve + * Handle recursive functions and arbitrary function + * references to other functions, properly pass + * function parameters and save function results. + * * Revision 1.58 1999/08/31 22:38:29 steve * Elaborate and emit to vvm procedural functions. * diff --git a/t-vvm.cc b/t-vvm.cc index 362ad98a0..06f55e2c8 100644 --- a/t-vvm.cc +++ b/t-vvm.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: t-vvm.cc,v 1.36 1999/08/31 22:38:29 steve Exp $" +#ident "$Id: t-vvm.cc,v 1.37 1999/09/01 20:46:19 steve Exp $" #endif # include @@ -206,11 +206,38 @@ void vvm_proc_rval::expr_subsignal(const NetESubSignal*sig) result = val; } +/* + * A function call is handled by assigning the parameters from the + * input expressions, then calling the function. After the function + * returns, copy the result into a temporary variable. + * + * Function calls are different from tasks in this regard--tasks had + * all this assigning arranged during elaboration. For functions, we + * must do it ourselves. + */ void vvm_proc_rval::expr_ufunc(const NetEUFunc*expr) { - string name = mangle(expr->name()); - os_ << " " << name << "(sim_);" << endl; - result = mangle(expr->result()->name()) + "_bits"; + const NetFuncDef*def = expr->definition(); + const unsigned pcnt = expr->parm_count(); + assert(pcnt == (def->port_count()-1)); + + /* Scan the parameter expressions, and assign the values to + the parameter port register. */ + for (unsigned idx = 0 ; idx < pcnt ; idx += 1) { + expr->parm(idx)->expr_scan(this); + os_ << " " << mangle(def->port(idx+1)->name()) << + "_bits = " << result << ";" << endl; + } + + /* Make the function call. */ + os_ << " " << mangle(expr->name()) << "(sim_);" << endl; + + /* Save the return value in a temporary. */ + result = make_temp(); + string rbits = mangle(expr->result()->name()) + "_bits"; + + os_ << " vvm_bitset_t<" << expr->expr_width() << "> " << + result << " = " << rbits << ";" << endl; } void vvm_proc_rval::expr_unary(const NetEUnary*expr) @@ -537,10 +564,13 @@ void target_vvm::func_def(ostream&os, const NetFuncDef*def) thread_step_ = 0; const string name = mangle(def->name()); os << "// Function " << def->name() << endl; - os << "static void " << name << "(vvm_simulation*sim_)" << endl; - os << "{" << endl; - def->proc()->emit_proc(os, this); - os << "}" << endl; + os << "static void " << name << "(vvm_simulation*);" << endl; + + delayed << "// Function " << def->name() << endl; + delayed << "static void " << name << "(vvm_simulation*sim_)" << endl; + delayed << "{" << endl; + def->proc()->emit_proc(delayed, this); + delayed << "}" << endl; } /* @@ -1191,19 +1221,6 @@ void target_vvm::proc_stask(ostream&os, const NetSTask*net) { string ptmp = make_temp(); -#if 0 - os << " struct __vpiHandle " << ptmp << "[" << - net->nparms() << "];" << endl; - for (unsigned idx = 0 ; idx < net->nparms() ; idx += 1) - if (net->parm(idx)) { - string val = emit_parm_rval(os, net->parm(idx)); - os << " vvm_make_vpi_parm(&" << ptmp << "[" - << idx << "], " << val << ");" << endl; - } else { - os << " vvm_make_vpi_parm(&" << ptmp << "[" - << idx << "]);" << endl; - } -#else os << " vpiHandle " << ptmp << "[" << net->nparms() << "];" << endl; for (unsigned idx = 0 ; idx < net->nparms() ; idx += 1) { @@ -1221,7 +1238,6 @@ void target_vvm::proc_stask(ostream&os, const NetSTask*net) os << " " << ptmp << "[" << idx << "] = " << val << ";" << endl; } -#endif os << " vvm_calltask(sim_, \"" << net->name() << "\", " << net->nparms() << ", " << ptmp << ");" << endl; @@ -1385,6 +1401,11 @@ extern const struct target tgt_vvm = { }; /* * $Log: t-vvm.cc,v $ + * Revision 1.37 1999/09/01 20:46:19 steve + * Handle recursive functions and arbitrary function + * references to other functions, properly pass + * function parameters and save function results. + * * Revision 1.36 1999/08/31 22:38:29 steve * Elaborate and emit to vvm procedural functions. *