Elaborate task input ports.

This commit is contained in:
steve 1999-07-24 02:11:19 +00:00
parent 9021f68996
commit 93a77a2efd
11 changed files with 325 additions and 74 deletions

View File

@ -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<PWire*>*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.
*

10
PTask.h
View File

@ -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 <string>
class Design;
class PWire;
class Statement;
/*
@ -33,13 +35,14 @@ class Statement;
class PTask : public LineInfo {
public:
explicit PTask(Statement*s);
explicit PTask(svector<PWire*>*p, Statement*s);
~PTask();
virtual void elaborate(Design*des, const string&path) const;
void dump(ostream&, unsigned) const;
private:
svector<PWire*>*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.
*

View File

@ -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.
*

View File

@ -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
{
svector<NetExpr*>eparms (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.) */
svector<NetNet*>ports (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<string,Module*>&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.

View File

@ -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 <cassert>
@ -535,15 +535,13 @@ const NetExpr* NetSTask::parm(unsigned idx) const
return parms_[idx];
}
NetUTask::NetUTask(NetTaskDef*def, const svector<NetExpr*>&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<NetNet*>&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.

View File

@ -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<NetNet*>&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_;
svector<NetNet*>ports_;
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<NetExpr*>&);
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_;
svector<NetExpr*>parms_;
};
/*
@ -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.

View File

@ -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.

32
parse.y
View File

@ -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 <wire> port
%type <wires> list_of_ports list_of_ports_opt
%type <wires> task_item task_item_list task_item_list_opt
%type <portname> port_name
%type <portnames> 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<PWire*>*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<PWire*>*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<PWire*>*tmp
= pform_make_task_ports(NetNet::PINOUT, $2, $3);
delete $2;
delete $3;
$$ = tmp;
}
;
task_item_list
: task_item_list task_item
{ svector<PWire*>*tmp = new svector<PWire*>(*$1, *$2);
delete $1;
delete $2;
$$ = tmp;
}
| task_item
{ $$ = $1; }
;
task_item_list_opt
: task_item_list
{ $$ = $1; }
|
{ $$ = 0; }
;
udp_body

View File

@ -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<PWire*>*pform_make_task_ports(NetNet::PortType pt,
const svector<PExpr*>*range,
const list<string>*names)
{
svector<PWire*>*res = new svector<PWire*>(0);
for (list<string>::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<PWire*>*tmp = new svector<PWire*>(*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<PExpr*>*parms)
{
if (parms == 0)
parms = new svector<PExpr*>(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<string,Module*>&modules,
@ -593,6 +638,9 @@ int pform_parse(const char*path, map<string,Module*>&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.
*

13
pform.h
View File

@ -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<lgate>*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<PWire*>*pform_make_task_ports(NetNet::PortType pt,
const svector<PExpr*>*range,
const list<string>*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.
*

View File

@ -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.
*