diff --git a/PTask.cc b/PTask.cc index eadbd3c29..b2f6e46b2 100644 --- a/PTask.cc +++ b/PTask.cc @@ -17,13 +17,13 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: PTask.cc,v 1.1 1999/07/03 02:12:51 steve Exp $" +#ident "$Id: PTask.cc,v 1.2 1999/07/24 02:11:19 steve Exp $" #endif # include "PTask.h" -PTask::PTask(Statement*s) -: statement_(s) +PTask::PTask(svector*p, Statement*s) +: ports_(p), statement_(s) { } @@ -33,6 +33,9 @@ PTask::~PTask() /* * $Log: PTask.cc,v $ + * Revision 1.2 1999/07/24 02:11:19 steve + * Elaborate task input ports. + * * Revision 1.1 1999/07/03 02:12:51 steve * Elaborate user defined tasks. * diff --git a/PTask.h b/PTask.h index bcee8dbc0..22a8c2b8c 100644 --- a/PTask.h +++ b/PTask.h @@ -19,12 +19,14 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: PTask.h,v 1.1 1999/07/03 02:12:51 steve Exp $" +#ident "$Id: PTask.h,v 1.2 1999/07/24 02:11:19 steve Exp $" #endif # include "LineInfo.h" +# include "svector.h" # include class Design; +class PWire; class Statement; /* @@ -33,13 +35,14 @@ class Statement; class PTask : public LineInfo { public: - explicit PTask(Statement*s); + explicit PTask(svector*p, Statement*s); ~PTask(); virtual void elaborate(Design*des, const string&path) const; void dump(ostream&, unsigned) const; private: + svector*ports_; Statement*statement_; private: // Not implemented @@ -49,6 +52,9 @@ class PTask : public LineInfo { /* * $Log: PTask.h,v $ + * Revision 1.2 1999/07/24 02:11:19 steve + * Elaborate task input ports. + * * Revision 1.1 1999/07/03 02:12:51 steve * Elaborate user defined tasks. * diff --git a/design_dump.cc b/design_dump.cc index d81ccd92c..7463ecd0f 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.32 1999/07/17 19:50:59 steve Exp $" +#ident "$Id: design_dump.cc,v 1.33 1999/07/24 02:11:20 steve Exp $" #endif /* @@ -196,7 +196,28 @@ void NetLogic::dump_node(ostream&o, unsigned ind) const void NetTaskDef::dump(ostream&o, unsigned ind) const { o << setw(ind) << "" << "task " << name_ << ";" << endl; + + for (unsigned idx = 0 ; idx < ports_.count() ; idx += 1) { + o << setw(ind+4) << ""; + switch (ports_[idx]->port_type()) { + case NetNet::PINPUT: + o << "input "; + break; + case NetNet::POUTPUT: + o << "output "; + break; + case NetNet::PINOUT: + o << "input "; + break; + default: + o << "NOT_A_PORT "; + break; + } + o << ports_[idx]->name() << ";" << endl; + } + proc_->dump(o, ind+4); + o << setw(ind) << "" << "endtask" << endl; } @@ -480,22 +501,7 @@ void NetSTask::dump(ostream&o, unsigned ind) const void NetUTask::dump(ostream&o, unsigned ind) const { - o << setw(ind) << "" << task_->name(); - - if (parms_.count() > 0) { - o << "("; - if (parms_[0]) - parms_[0]->dump(o); - - for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { - o << ", "; - if (parms_[idx]) - parms_[idx]->dump(o); - } - - o << ")"; - } - o << ";" << endl; + o << setw(ind) << "" << task_->name() << ";" << endl; } void NetWhile::dump(ostream&o, unsigned ind) const @@ -684,6 +690,9 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.33 1999/07/24 02:11:20 steve + * Elaborate task input ports. + * * Revision 1.32 1999/07/17 19:50:59 steve * netlist support for ternary operator. * diff --git a/elaborate.cc b/elaborate.cc index d7663ff64..f0f318ad2 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.58 1999/07/18 21:17:50 steve Exp $" +#ident "$Id: elaborate.cc,v 1.59 1999/07/24 02:11:20 steve Exp $" #endif /* @@ -103,6 +103,8 @@ void PWire::elaborate(Design*des, const string&path) const NetNet::Type wtype = type_; if (wtype == NetNet::IMPLICIT) wtype = NetNet::WIRE; + if (wtype == NetNet::IMPLICIT_REG) + wtype = NetNet::REG; unsigned wid = 1; @@ -1533,15 +1535,36 @@ NetProc* PCallTask::elaborate_sys(Design*des, const string&path) const return cur; } +/* + * A call to a user defined task is different from a call to a system + * task because a user task in a netlist has no parameters: the + * assignments are done by the calling thread. For example: + * + * task foo; + * input a; + * output b; + * [...] + * endtask; + * + * [...] foo(x, y); + * + * is really: + * + * task foo; + * reg a; + * reg b; + * [...] + * endtask; + * + * [...] + * begin + * a = x; + * foo; + * y = b; + * end + */ NetProc* PCallTask::elaborate_usr(Design*des, const string&path) const { - svectoreparms (nparms()); - - for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { - PExpr*ex = parm(idx); - eparms[idx] = ex? ex->elaborate_expr(des, path) : 0; - } - NetTaskDef*def = des->find_task(path + "." + name_); if (def == 0) { cerr << get_line() << ": Enable of unknown task ``" << @@ -1550,8 +1573,60 @@ NetProc* PCallTask::elaborate_usr(Design*des, const string&path) const return 0; } - NetUTask*cur = new NetUTask(def, eparms); - return cur; + if (nparms() != def->port_count()) { + cerr << get_line() << ": Port count mismatch in call to ``" + << name_ << "''." << endl; + des->errors += 1; + return 0; + } + + NetUTask*cur; + + /* Handle tasks with no parameters specially. There is no need + to make a sequential block to hold the generated code. */ + if (nparms() == 0) { + cur = new NetUTask(def); + return cur; + } + + NetBlock*block = new NetBlock(NetBlock::SEQU); + + /* Generate assignment statement statements for the input and + INOUT ports of the task. */ + for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { + + NetNet*port = def->port(idx); + assert(port->port_type() != NetNet::NOT_A_PORT); + if (port->port_type() == NetNet::POUTPUT) + continue; + + NetExpr*rv = parms_[idx]->elaborate_expr(des, path); + NetAssign*pr = new NetAssign("@", des, port->pin_count(), rv); + for (unsigned pi = 0 ; pi < port->pin_count() ; pi += 1) + connect(port->pin(pi), pr->pin(pi)); + des->add_node(pr); + block->append(pr); + } + + /* Generate the task call proper... */ + cur = new NetUTask(def); + block->append(cur); + + /* Generate assignment statement statements for the output and + INOUT ports of the task. */ + for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { + + NetNet*port = def->port(idx); + assert(port->port_type() != NetNet::NOT_A_PORT); + if (port->port_type() == NetNet::PINPUT) + continue; + + cerr << get_line() << ": Sorry, output ports not yet " + "implemented." << endl; + des->errors += 1; + } + + return block; } NetProc* PDelayStatement::elaborate(Design*des, const string&path) const @@ -1725,7 +1800,9 @@ NetProc* PRepeat::elaborate(Design*des, const string&path) const /* * A task definition is elaborated by elaborating the statement that - * it contains, and ... XXXX + * it contains, and connecting its ports to NetNet objects. The + * netlist doesn't really need the array of parameters once elaboration + * is complete, but this is the best place to store them. */ void PTask::elaborate(Design*des, const string&path) const { @@ -1737,8 +1814,19 @@ void PTask::elaborate(Design*des, const string&path) const return; } - NetTaskDef*def = new NetTaskDef(path, st); + /* 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 + calls to the task. (Remember, the task itself does not need + these ports.) */ + svectorports (ports_->count()); + for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) { + NetNet*tmp = des->find_signal(path, (*ports_)[idx]->name()); + ports[idx] = tmp; + } + + NetTaskDef*def = new NetTaskDef(path, st, ports); des->add_task(path, def); } @@ -1862,6 +1950,9 @@ Design* elaborate(const map&modules, /* * $Log: elaborate.cc,v $ + * Revision 1.59 1999/07/24 02:11:20 steve + * Elaborate task input ports. + * * Revision 1.58 1999/07/18 21:17:50 steve * Add support for CE input to XNF DFF, and do * complete cleanup of replaced design nodes. diff --git a/netlist.cc b/netlist.cc index 4d82caa69..99b3a1ece 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.47 1999/07/18 21:17:50 steve Exp $" +#ident "$Id: netlist.cc,v 1.48 1999/07/24 02:11:20 steve Exp $" #endif # include @@ -535,15 +535,13 @@ const NetExpr* NetSTask::parm(unsigned idx) const return parms_[idx]; } -NetUTask::NetUTask(NetTaskDef*def, const svector&p) -: task_(def), parms_(p) +NetUTask::NetUTask(NetTaskDef*def) +: task_(def) { } NetUTask::~NetUTask() { - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) - delete parms_[idx]; } NetExpr::~NetExpr() @@ -968,8 +966,8 @@ const NetExpr* NetRepeat::expr() const return expr_; } -NetTaskDef::NetTaskDef(const string&n, NetProc*p) -: name_(n), proc_(p) +NetTaskDef::NetTaskDef(const string&n, NetProc*p, const svector&po) +: name_(n), proc_(p), ports_(po) { } @@ -978,6 +976,12 @@ NetTaskDef::~NetTaskDef() delete proc_; } +NetNet* NetTaskDef::port(unsigned idx) +{ + assert(idx < ports_.count()); + return ports_[idx]; +} + NetUDP::NetUDP(const string&n, unsigned pins, bool sequ) : NetNode(n, pins), sequential_(sequ), init_('x') { @@ -1479,6 +1483,9 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*)) /* * $Log: netlist.cc,v $ + * Revision 1.48 1999/07/24 02:11:20 steve + * Elaborate task input ports. + * * Revision 1.47 1999/07/18 21:17:50 steve * Add support for CE input to XNF DFF, and do * complete cleanup of replaced design nodes. diff --git a/netlist.h b/netlist.h index d8dd49c12..17a5e13d8 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.50 1999/07/18 21:17:50 steve Exp $" +#ident "$Id: netlist.h,v 1.51 1999/07/24 02:11:20 steve Exp $" #endif /* @@ -217,8 +217,8 @@ class NetNode : public NetObj { class NetNet : public NetObj, public LineInfo { public: - enum Type { IMPLICIT, WIRE, TRI, TRI1, SUPPLY0, WAND, TRIAND, - TRI0, SUPPLY1, WOR, TRIOR, REG, INTEGER }; + enum Type { IMPLICIT, IMPLICIT_REG, WIRE, TRI, TRI1, SUPPLY0, + WAND, TRIAND, TRI0, SUPPLY1, WOR, TRIOR, REG, INTEGER }; enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT }; @@ -885,17 +885,21 @@ class NetSTask : public NetProc { class NetTaskDef { public: - NetTaskDef(const string&n, NetProc*p); + NetTaskDef(const string&n, NetProc*p, const svector&po); ~NetTaskDef(); const string& name() const { return name_; } const NetProc*proc() const { return proc_; } + unsigned port_count() const { return ports_.count(); } + NetNet*port(unsigned idx); + void dump(ostream&, unsigned) const; private: string name_; NetProc*proc_; + svectorports_; private: // not implemented NetTaskDef(const NetTaskDef&); @@ -903,26 +907,21 @@ class NetTaskDef { }; /* - * A call to a user defined task is elaborated into this object. I - * save the parameters and the pointer to the task definition. + * A call to a user defined task is elaborated into this object. */ class NetUTask : public NetProc { public: - NetUTask(NetTaskDef*, const svector&); + NetUTask(NetTaskDef*); ~NetUTask(); const string& name() const { return task_->name(); } - unsigned nparms() const { return parms_.count(); } - - const NetExpr* parm(unsigned idx) const; virtual void emit_proc(ostream&, struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; private: NetTaskDef*task_; - svectorparms_; }; /* @@ -1376,6 +1375,9 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.51 1999/07/24 02:11:20 steve + * Elaborate task input ports. + * * Revision 1.50 1999/07/18 21:17:50 steve * Add support for CE input to XNF DFF, and do * complete cleanup of replaced design nodes. diff --git a/netlist.txt b/netlist.txt index cf943a959..4db97e344 100644 --- a/netlist.txt +++ b/netlist.txt @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ident "$Id: netlist.txt,v 1.2 1999/07/21 01:15:29 steve Exp $" +#ident "$Id: netlist.txt,v 1.3 1999/07/24 02:11:20 steve Exp $" Note that the netlist.h header contains detailed descriptions of how @@ -155,10 +155,43 @@ connect to and receive signals from the structural aspects of the design. The pins of a NetESignal object are passive. The values at the pin are -only sampled with the process evaluates the expression that includes +only sampled when the process evaluates the expression that includes the NetESignal object. +HIERARCHY IN NETLISTS + +The obvious hierarchical structure of verilog is the module. The +Verilog program may contain any number of instantiations of modules in +order to form an hierarchical design. However, the elaboration of the +design into a netlist erases module boundaries. Modules are expanded +each place they are used, with the hierarchical instance name used to +name the components of the module instance. However, the fact that a +wire or register is a module port is lost. + +The advantage of this behavior is first the simplification of the +netlist structure itself. Backends that process netlists only need to +cope with a list of nets, a list of nodes and a list of +processes. This eases the task of the backend code generators. + +Another advantage of this flattening of the netlist is that optimizers +can operate globally, with optimizations freely crossing module +boundaries. This makes coding of netlist transform functions such as +constant propagation more effective and easier to write. + +TASKS IN NETLISTS + +The flattening of the design does not include tasks and named +begin-end blocks. Tasks are behavioral hierarchy (whereas modules are +structural) so do not easily succumb to the flattening process. In +particular, it is logically impossible to flatten tasks that +recurse. (The elaboration process does reserve the right to flatten +some task calls. C++ programmers recognize this as inlining a task.) + + $Log: netlist.txt,v $ + Revision 1.3 1999/07/24 02:11:20 steve + Elaborate task input ports. + Revision 1.2 1999/07/21 01:15:29 steve Document netlist semantics. diff --git a/parse.y b/parse.y index 46a9e195d..c6ed0e987 100644 --- a/parse.y +++ b/parse.y @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: parse.y,v 1.51 1999/07/12 00:59:36 steve Exp $" +#ident "$Id: parse.y,v 1.52 1999/07/24 02:11:20 steve Exp $" #endif # include "parse_misc.h" @@ -107,6 +107,7 @@ extern void lex_end_table(); %type port %type list_of_ports list_of_ports_opt +%type task_item task_item_list task_item_list_opt %type port_name %type port_name_list @@ -1542,32 +1543,53 @@ statement_opt task_body : task_item_list_opt statement_opt - { PTask*tmp = new PTask($2); + { PTask*tmp = new PTask($1, $2); $$ = tmp; } ; task_item : block_item_decl + { $$ = 0; } | K_input range_opt list_of_variables ';' - { yyerror(@1, "Sorry, task input ports not implemented."); + { svector*tmp + = pform_make_task_ports(NetNet::PINPUT, $2, $3); + delete $2; + delete $3; + $$ = tmp; } | K_output range_opt list_of_variables ';' - { yyerror(@1, "Sorry, task output ports not implemented."); + { svector*tmp + = pform_make_task_ports(NetNet::POUTPUT, $2, $3); + delete $2; + delete $3; + $$ = tmp; } | K_inout range_opt list_of_variables ';' - { yyerror(@1, "Sorry, task inout ports not implemented."); + { svector*tmp + = pform_make_task_ports(NetNet::PINOUT, $2, $3); + delete $2; + delete $3; + $$ = tmp; } ; task_item_list : task_item_list task_item + { svector*tmp = new svector(*$1, *$2); + delete $1; + delete $2; + $$ = tmp; + } | task_item + { $$ = $1; } ; task_item_list_opt : task_item_list + { $$ = $1; } | + { $$ = 0; } ; udp_body diff --git a/pform.cc b/pform.cc index 741b32c7d..f1733980f 100644 --- a/pform.cc +++ b/pform.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: pform.cc,v 1.32 1999/07/10 01:03:18 steve Exp $" +#ident "$Id: pform.cc,v 1.33 1999/07/24 02:11:20 steve Exp $" #endif # include "compiler.h" @@ -426,6 +426,63 @@ void pform_set_port_type(const string&name, NetNet::PortType pt) VLerror("error setting port direction."); } +/* + * This function is called by the parser to create task ports. The + * resulting wire (which should be a register) is put into a list to + * be packed into the task parameter list. + * + * It is possible that the wire (er, register) was already created, + * but we know that if the name matches it is a part of the current + * task, so in that case I just assign direction to it. + * + * The following example demonstrates some if the issues: + * + * task foo; + * input a; + * reg a, b; + * input b; + * [...] + * endtask + * + * This function is called when the parser matches the "input a" and + * the "input b" statements. For ``a'', this function is called before + * the wire is declared as a register, so I create the foo.a + * wire. For ``b'', I will find that there is already a foo.b and I + * just set the port direction. In either case, the ``reg a, b'' + * statement is caught by the block_item non-terminal and processed there. + */ +svector*pform_make_task_ports(NetNet::PortType pt, + const svector*range, + const list*names) +{ + svector*res = new svector(0); + for (list::const_iterator cur = names->begin() + ; cur != names->end() ; cur ++ ) { + + string name = scoped_name(*cur); + + /* Look for a preexisting wire. If it exists, set the + port direction. If not, create it. */ + PWire*curw = pform_cur_module->get_wire(name); + if (curw) { + curw->set_port_type(pt); + } else { + curw = new PWire(name, NetNet::IMPLICIT_REG, pt); + pform_cur_module->add_wire(curw); + } + + /* If there is a range involved, it needs to be set. */ + if (range) + curw->set_range((*range)[0], (*range)[1]); + + svector*tmp = new svector(*res, curw); + delete res; + res = tmp; + } + + return res; +} + void pform_set_task(const string&name, PTask*task) { pform_cur_module->add_task(name, task); @@ -554,18 +611,6 @@ PProcess* pform_make_behavior(PProcess::Type type, Statement*st) return pp; } -#if 0 -Statement* pform_make_calltask(string*name, svector*parms) -{ - if (parms == 0) - parms = new svector(0); - - PCallTask*ct = new PCallTask(*name, *parms); - delete name; - delete parms; - return ct; -} -#endif FILE*vl_input = 0; int pform_parse(const char*path, map&modules, @@ -593,6 +638,9 @@ int pform_parse(const char*path, map&modules, /* * $Log: pform.cc,v $ + * Revision 1.33 1999/07/24 02:11:20 steve + * Elaborate task input ports. + * * Revision 1.32 1999/07/10 01:03:18 steve * remove string from lexical phase. * diff --git a/pform.h b/pform.h index 02b6b3c46..02b2d97d8 100644 --- a/pform.h +++ b/pform.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: pform.h,v 1.23 1999/07/10 01:03:18 steve Exp $" +#ident "$Id: pform.h,v 1.24 1999/07/24 02:11:20 steve Exp $" #endif # include "netlist.h" @@ -145,6 +145,14 @@ extern void pform_make_modgates(const string&type, svector*gates); /* Make a continuous assignment node, with optional bit- or part- select. */ extern PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval); + +/* Given a port type and a list of names, make a list of wires that + can be used as task port information. */ +extern svector*pform_make_task_ports(NetNet::PortType pt, + const svector*range, + const list*names); + + /* * These are functions that the outside-the-parser code uses the do * interesting things to the verilog. The parse function reads and @@ -157,6 +165,9 @@ extern void pform_dump(ostream&out, Module*mod); /* * $Log: pform.h,v $ + * Revision 1.24 1999/07/24 02:11:20 steve + * Elaborate task input ports. + * * Revision 1.23 1999/07/10 01:03:18 steve * remove string from lexical phase. * diff --git a/pform_dump.cc b/pform_dump.cc index 618e0fb1a..e7598d3bf 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: pform_dump.cc,v 1.28 1999/07/17 19:51:00 steve Exp $" +#ident "$Id: pform_dump.cc,v 1.29 1999/07/24 02:11:20 steve Exp $" #endif /* @@ -409,6 +409,22 @@ void PRepeat::dump(ostream&out, unsigned ind) const void PTask::dump(ostream&out, unsigned ind) const { + for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) { + out << setw(ind) << ""; + switch ((*ports_)[idx]->get_port_type()) { + case NetNet::PINPUT: + out << "input "; + break; + case NetNet::POUTPUT: + out << "output "; + break; + case NetNet::PINOUT: + out << "inout "; + break; + } + out << (*ports_)[idx]->name() << ";" << endl; + } + statement_->dump(out, ind); } @@ -530,6 +546,9 @@ void PUdp::dump(ostream&out) const /* * $Log: pform_dump.cc,v $ + * Revision 1.29 1999/07/24 02:11:20 steve + * Elaborate task input ports. + * * Revision 1.28 1999/07/17 19:51:00 steve * netlist support for ternary operator. *