Elaborate user defined tasks.
This commit is contained in:
parent
484485e299
commit
3ff6912bdd
|
|
@ -18,7 +18,7 @@
|
|||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.5 1999/06/17 05:34:42 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.6 1999/07/03 02:12:51 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
|
@ -55,7 +55,8 @@ FF = nobufz.o propinit.o sigfold.o stupid.o xnfio.o
|
|||
|
||||
O = main.o cprop.o design_dump.o elaborate.o emit.o eval.o lexor.o mangle.o \
|
||||
netlist.o parse.o parse_misc.o pform.o pform_dump.o verinum.o verireal.o \
|
||||
target.o targets.o Module.o PExpr.o PGate.o PWire.o Statement.o $(FF) $(TT)
|
||||
target.o targets.o Module.o PExpr.o PGate.o PTask.o PWire.o Statement.o \
|
||||
$(FF) $(TT)
|
||||
|
||||
Makefile: Makefile.in config.status
|
||||
./config.status
|
||||
|
|
|
|||
10
Module.cc
10
Module.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: Module.cc,v 1.2 1999/06/17 05:34:42 steve Exp $"
|
||||
#ident "$Id: Module.cc,v 1.3 1999/07/03 02:12:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "Module.h"
|
||||
|
|
@ -28,6 +28,11 @@ void Module::add_gate(PGate*gate)
|
|||
gates_.push_back(gate);
|
||||
}
|
||||
|
||||
void Module::add_task(const string&name, PTask*task)
|
||||
{
|
||||
tasks_[name] = task;
|
||||
}
|
||||
|
||||
void Module::add_wire(PWire*wire)
|
||||
{
|
||||
wires_.push_back(wire);
|
||||
|
|
@ -54,6 +59,9 @@ PWire* Module::get_wire(const string&name)
|
|||
|
||||
/*
|
||||
* $Log: Module.cc,v $
|
||||
* Revision 1.3 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.2 1999/06/17 05:34:42 steve
|
||||
* Clean up interface of the PWire class,
|
||||
* Properly match wire ranges.
|
||||
|
|
|
|||
9
Module.h
9
Module.h
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: Module.h,v 1.4 1999/06/15 03:44:53 steve Exp $"
|
||||
#ident "$Id: Module.h,v 1.5 1999/07/03 02:12:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <list>
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
# include <string>
|
||||
class PExpr;
|
||||
class PGate;
|
||||
class PTask;
|
||||
class PWire;
|
||||
class PProcess;
|
||||
class Design;
|
||||
|
|
@ -55,6 +56,7 @@ class Module {
|
|||
void add_gate(PGate*gate);
|
||||
void add_wire(PWire*wire);
|
||||
void add_behavior(PProcess*behave);
|
||||
void add_task(const string&name, PTask*def);
|
||||
|
||||
// Find a wire by name. This is used for connecting gates to
|
||||
// existing wires, etc.
|
||||
|
|
@ -64,6 +66,7 @@ class Module {
|
|||
const list<PGate*>& get_gates() const { return gates_; }
|
||||
const list<PProcess*>& get_behaviors() const { return behaviors_; }
|
||||
|
||||
void dump(ostream&out) const;
|
||||
bool elaborate(Design*, const string&path) const;
|
||||
|
||||
private:
|
||||
|
|
@ -72,6 +75,7 @@ class Module {
|
|||
list<PWire*> wires_;
|
||||
list<PGate*> gates_;
|
||||
list<PProcess*> behaviors_;
|
||||
map<string,PTask*> tasks_;
|
||||
|
||||
private: // Not implemented
|
||||
Module(const Module&);
|
||||
|
|
@ -81,6 +85,9 @@ class Module {
|
|||
|
||||
/*
|
||||
* $Log: Module.h,v $
|
||||
* Revision 1.5 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.4 1999/06/15 03:44:53 steve
|
||||
* Get rid of the STL vector template.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* 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 $"
|
||||
#endif
|
||||
|
||||
# include "PTask.h"
|
||||
|
||||
PTask::PTask(Statement*s)
|
||||
: statement_(s)
|
||||
{
|
||||
}
|
||||
|
||||
PTask::~PTask()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: PTask.cc,v $
|
||||
* Revision 1.1 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#ifndef __PTask_H
|
||||
#define __PTask_H
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* 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 $"
|
||||
#endif
|
||||
|
||||
# include "LineInfo.h"
|
||||
# include <string>
|
||||
class Design;
|
||||
class Statement;
|
||||
|
||||
/*
|
||||
* The PTask holds the parsed definitions of a task.
|
||||
*/
|
||||
class PTask : public LineInfo {
|
||||
|
||||
public:
|
||||
explicit PTask(Statement*s);
|
||||
~PTask();
|
||||
|
||||
virtual void elaborate(Design*des, const string&path) const;
|
||||
void dump(ostream&, unsigned) const;
|
||||
|
||||
private:
|
||||
Statement*statement_;
|
||||
|
||||
private: // Not implemented
|
||||
PTask(const PTask&);
|
||||
PTask& operator=(const PTask&);
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: PTask.h,v $
|
||||
* Revision 1.1 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: Statement.h,v 1.13 1999/06/24 04:24:18 steve Exp $"
|
||||
#ident "$Id: Statement.h,v 1.14 1999/07/03 02:12:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
|
|
@ -173,6 +173,9 @@ class PCallTask : public Statement {
|
|||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
NetProc* elaborate_sys(Design*des, const string&path) const;
|
||||
NetProc* elaborate_usr(Design*des, const string&path) const;
|
||||
|
||||
const string name_;
|
||||
svector<PExpr*> parms_;
|
||||
};
|
||||
|
|
@ -327,6 +330,9 @@ class PWhile : public Statement {
|
|||
|
||||
/*
|
||||
* $Log: Statement.h,v $
|
||||
* Revision 1.14 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.13 1999/06/24 04:24:18 steve
|
||||
* Handle expression widths for EEE and NEE operators,
|
||||
* add named blocks and scope handling,
|
||||
|
|
|
|||
|
|
@ -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.30 1999/06/19 21:06:16 steve Exp $"
|
||||
#ident "$Id: design_dump.cc,v 1.31 1999/07/03 02:12:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -193,6 +193,13 @@ void NetLogic::dump_node(ostream&o, unsigned ind) const
|
|||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetTaskDef::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "task " << name_ << ";" << endl;
|
||||
proc_->dump(o, ind+4);
|
||||
o << setw(ind) << "" << "endtask" << endl;
|
||||
}
|
||||
|
||||
void NetUDP::dump_sequ_(ostream&o, unsigned ind) const
|
||||
{
|
||||
string tmp = "";
|
||||
|
|
@ -445,16 +452,22 @@ void NetNEvent::dump_proc(ostream&o) const
|
|||
o << name();
|
||||
}
|
||||
|
||||
void NetTask::dump(ostream&o, unsigned ind) const
|
||||
void NetRepeat::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "repeat (" << *expr_ << ")" << endl;
|
||||
statement_->dump(o, ind+2);
|
||||
}
|
||||
|
||||
void NetSTask::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << name_;
|
||||
|
||||
if (nparms_ > 0) {
|
||||
if (parms_.count() > 0) {
|
||||
o << "(";
|
||||
if (parms_[0])
|
||||
parms_[0]->dump(o);
|
||||
|
||||
for (unsigned idx = 1 ; idx < nparms_ ; idx += 1) {
|
||||
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
|
||||
o << ", ";
|
||||
if (parms_[idx])
|
||||
parms_[idx]->dump(o);
|
||||
|
|
@ -465,10 +478,24 @@ void NetTask::dump(ostream&o, unsigned ind) const
|
|||
o << ";" << endl;
|
||||
}
|
||||
|
||||
void NetRepeat::dump(ostream&o, unsigned ind) const
|
||||
void NetUTask::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "repeat (" << *expr_ << ")" << endl;
|
||||
statement_->dump(o, ind+2);
|
||||
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;
|
||||
}
|
||||
|
||||
void NetWhile::dump(ostream&o, unsigned ind) const
|
||||
|
|
@ -621,6 +648,15 @@ void Design::dump(ostream&o) const
|
|||
}
|
||||
}
|
||||
|
||||
o << "ELABORATED TASK DEFINITIONS:" << endl;
|
||||
{
|
||||
map<string,NetTaskDef*>::const_iterator pp;
|
||||
for (pp = tasks_.begin()
|
||||
; pp != tasks_.end() ; pp ++) {
|
||||
(*pp).second->dump(o, 0);
|
||||
}
|
||||
}
|
||||
|
||||
o << "ELABORATED NODES:" << endl;
|
||||
|
||||
// dump the nodes,
|
||||
|
|
@ -642,6 +678,9 @@ void Design::dump(ostream&o) const
|
|||
|
||||
/*
|
||||
* $Log: design_dump.cc,v $
|
||||
* Revision 1.31 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.30 1999/06/19 21:06:16 steve
|
||||
* Elaborate and supprort to vvm the forever
|
||||
* and repeat statements.
|
||||
|
|
|
|||
72
elaborate.cc
72
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.49 1999/06/24 04:45:29 steve Exp $"
|
||||
#ident "$Id: elaborate.cc,v 1.50 1999/07/03 02:12:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -1352,13 +1352,47 @@ NetProc* PCondit::elaborate(Design*des, const string&path) const
|
|||
|
||||
NetProc* PCallTask::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
NetTask*cur = new NetTask(name(), nparms());
|
||||
if (name_[0] == '$')
|
||||
return elaborate_sys(des, path);
|
||||
else
|
||||
return elaborate_usr(des, path);
|
||||
}
|
||||
|
||||
/*
|
||||
* A call to a system task involves elaborating all the parameters,
|
||||
* then passing the list to the NetSTask object.
|
||||
*/
|
||||
NetProc* PCallTask::elaborate_sys(Design*des, const string&path) const
|
||||
{
|
||||
svector<NetExpr*>eparms (nparms());
|
||||
|
||||
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
|
||||
PExpr*ex = parm(idx);
|
||||
cur->parm(idx, ex? ex->elaborate_expr(des, path) : 0);
|
||||
eparms[idx] = ex? ex->elaborate_expr(des, path) : 0;
|
||||
}
|
||||
|
||||
NetSTask*cur = new NetSTask(name(), eparms);
|
||||
return cur;
|
||||
}
|
||||
|
||||
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 ``" <<
|
||||
name_ << "''." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetUTask*cur = new NetUTask(def, eparms);
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
|
@ -1531,6 +1565,25 @@ NetProc* PRepeat::elaborate(Design*des, const string&path) const
|
|||
return proc;
|
||||
}
|
||||
|
||||
/*
|
||||
* A task definition is elaborated by elaborating the statement that
|
||||
* it contains, and ... XXXX
|
||||
*/
|
||||
void PTask::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
NetProc*st = statement_->elaborate(des, path);
|
||||
if (st == 0) {
|
||||
cerr << statement_->get_line() << ": Unable to elaborate "
|
||||
"statement in task " << path << " at " << get_line()
|
||||
<< "." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
NetTaskDef*def = new NetTaskDef(path, st);
|
||||
|
||||
des->add_task(path, def);
|
||||
}
|
||||
|
||||
/*
|
||||
* The while loop is fairly directly represented in the netlist.
|
||||
*/
|
||||
|
|
@ -1566,6 +1619,16 @@ bool Module::elaborate(Design*des, const string&path) const
|
|||
(*wt)->elaborate(des, path);
|
||||
}
|
||||
|
||||
// Elaborate the task definitions. This is done before the
|
||||
// behaviors so that task calls may reference these, and after
|
||||
// the signals so that the tasks can reference them.
|
||||
typedef map<string,PTask*>::const_iterator mtask_it_t;
|
||||
for (mtask_it_t cur = tasks_.begin()
|
||||
; cur != tasks_.end() ; cur ++) {
|
||||
string pname = path + "." + (*cur).first;
|
||||
(*cur).second->elaborate(des, pname);
|
||||
}
|
||||
|
||||
// Get all the gates of the module and elaborate them by
|
||||
// connecting them to the signals. The gate may be simple or
|
||||
// complex.
|
||||
|
|
@ -1641,6 +1704,9 @@ Design* elaborate(const map<string,Module*>&modules,
|
|||
|
||||
/*
|
||||
* $Log: elaborate.cc,v $
|
||||
* Revision 1.50 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.49 1999/06/24 04:45:29 steve
|
||||
* Elaborate wide structoral bitwise OR.
|
||||
*
|
||||
|
|
|
|||
22
emit.cc
22
emit.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: emit.cc,v 1.14 1999/06/19 21:06:16 steve Exp $"
|
||||
#ident "$Id: emit.cc,v 1.15 1999/07/03 02:12:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -145,9 +145,14 @@ void NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
|
|||
tgt->proc_repeat(o, this);
|
||||
}
|
||||
|
||||
void NetTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
void NetSTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_task(o, this);
|
||||
tgt->proc_stask(o, this);
|
||||
}
|
||||
|
||||
void NetUTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_utask(o, this);
|
||||
}
|
||||
|
||||
void NetWhile::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
|
|
@ -219,6 +224,14 @@ void Design::emit(ostream&o, struct target_t*tgt) const
|
|||
}
|
||||
|
||||
|
||||
// emit task definitions
|
||||
{
|
||||
map<string,NetTaskDef*>::const_iterator ta;
|
||||
for (ta = tasks_.begin() ; ta != tasks_.end() ; ta ++) {
|
||||
tgt->task_def(o, (*ta).second);
|
||||
}
|
||||
}
|
||||
|
||||
// emit nodes
|
||||
if (nodes_) {
|
||||
NetNode*cur = nodes_->node_next_;
|
||||
|
|
@ -295,6 +308,9 @@ void emit(ostream&o, const Design*des, const char*type)
|
|||
|
||||
/*
|
||||
* $Log: emit.cc,v $
|
||||
* Revision 1.15 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.14 1999/06/19 21:06:16 steve
|
||||
* Elaborate and supprort to vvm the forever
|
||||
* and repeat statements.
|
||||
|
|
|
|||
56
netlist.cc
56
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.40 1999/06/24 05:02:36 steve Exp $"
|
||||
#ident "$Id: netlist.cc,v 1.41 1999/07/03 02:12:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <cassert>
|
||||
|
|
@ -430,12 +430,33 @@ NetCondit::NetCondit(NetExpr*ex, NetProc*i, NetProc*e)
|
|||
{
|
||||
}
|
||||
|
||||
NetTask::~NetTask()
|
||||
NetSTask::NetSTask(const string&na, const svector<NetExpr*>&pa)
|
||||
: name_(na), parms_(pa)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < nparms_ ; idx += 1)
|
||||
assert(name_[0] == '$');
|
||||
}
|
||||
|
||||
NetSTask::~NetSTask()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
|
||||
delete parms_[idx];
|
||||
|
||||
delete[]parms_;
|
||||
}
|
||||
|
||||
const NetExpr* NetSTask::parm(unsigned idx) const
|
||||
{
|
||||
return parms_[idx];
|
||||
}
|
||||
|
||||
NetUTask::NetUTask(NetTaskDef*def, const svector<NetExpr*>&p)
|
||||
: task_(def), parms_(p)
|
||||
{
|
||||
}
|
||||
|
||||
NetUTask::~NetUTask()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
|
||||
delete parms_[idx];
|
||||
}
|
||||
|
||||
NetExpr::~NetExpr()
|
||||
|
|
@ -774,6 +795,16 @@ const NetExpr* NetRepeat::expr() const
|
|||
return expr_;
|
||||
}
|
||||
|
||||
NetTaskDef::NetTaskDef(const string&n, NetProc*p)
|
||||
: name_(n), proc_(p)
|
||||
{
|
||||
}
|
||||
|
||||
NetTaskDef::~NetTaskDef()
|
||||
{
|
||||
delete proc_;
|
||||
}
|
||||
|
||||
NetUDP::NetUDP(const string&n, unsigned pins, bool sequ)
|
||||
: NetNode(n, pins), sequential_(sequ), init_('x')
|
||||
{
|
||||
|
|
@ -1143,6 +1174,20 @@ NetMemory* Design::find_memory(const string&key)
|
|||
return (*cur).second;
|
||||
}
|
||||
|
||||
void Design::add_task(const string&key, NetTaskDef*def)
|
||||
{
|
||||
tasks_[key] = def;
|
||||
}
|
||||
|
||||
NetTaskDef* Design::find_task(const string&key)
|
||||
{
|
||||
map<string,NetTaskDef*>::const_iterator cur = tasks_.find(key);
|
||||
if (cur == tasks_.end())
|
||||
return 0;
|
||||
|
||||
return (*cur).second;
|
||||
}
|
||||
|
||||
void Design::add_node(NetNode*net)
|
||||
{
|
||||
assert(net->design_ == 0);
|
||||
|
|
@ -1250,6 +1295,9 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*))
|
|||
|
||||
/*
|
||||
* $Log: netlist.cc,v $
|
||||
* Revision 1.41 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.40 1999/06/24 05:02:36 steve
|
||||
* Properly terminate signal matching scan.
|
||||
*
|
||||
|
|
|
|||
221
netlist.h
221
netlist.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __netlist_H
|
||||
#define __netlist_H
|
||||
/*
|
||||
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -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.42 1999/06/24 04:24:18 steve Exp $"
|
||||
#ident "$Id: netlist.h,v 1.43 1999/07/03 02:12:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -33,6 +33,7 @@
|
|||
# include "verinum.h"
|
||||
# include "sref.h"
|
||||
# include "LineInfo.h"
|
||||
# include "svector.h"
|
||||
|
||||
class Design;
|
||||
class NetNode;
|
||||
|
|
@ -838,38 +839,76 @@ class NetRepeat : public NetProc {
|
|||
NetProc*statement_;
|
||||
};
|
||||
|
||||
/* The elaborator should expand all the user defined tasks in line, so
|
||||
this leaves the NetTask to represent activations of system tasks,
|
||||
or external tasks that are not known at compile time. */
|
||||
class NetTask : public NetProc {
|
||||
/*
|
||||
* The NetSTask class is a call to a system task. These kinds of tasks
|
||||
* are generally handled very simply in the target. They certainly are
|
||||
* handled differently from user defined tasks because ivl knows all
|
||||
* about the user defined tasks.
|
||||
*/
|
||||
class NetSTask : public NetProc {
|
||||
|
||||
public:
|
||||
NetTask(const string&na, unsigned np)
|
||||
: name_(na), nparms_(np)
|
||||
{ parms_ = new NetExpr*[nparms_]; }
|
||||
~NetTask();
|
||||
NetSTask(const string&na, const svector<NetExpr*>&);
|
||||
~NetSTask();
|
||||
|
||||
const string& name() const { return name_; }
|
||||
|
||||
unsigned nparms() const { return nparms_; }
|
||||
unsigned nparms() const { return parms_.count(); }
|
||||
|
||||
void parm(unsigned idx, NetExpr*p)
|
||||
{ assert(idx < nparms_);
|
||||
parms_[idx] = p;
|
||||
}
|
||||
|
||||
const NetExpr* parm(unsigned idx) const
|
||||
{ assert(idx < nparms_);
|
||||
return parms_[idx];
|
||||
}
|
||||
const NetExpr* parm(unsigned idx) const;
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
unsigned nparms_;
|
||||
NetExpr**parms_;
|
||||
svector<NetExpr*>parms_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class represents an elaborated class definition. NetUTask
|
||||
* classes may refer to objects of this type to get the meaning of the
|
||||
* defined task.
|
||||
*/
|
||||
class NetTaskDef {
|
||||
|
||||
public:
|
||||
NetTaskDef(const string&n, NetProc*p);
|
||||
~NetTaskDef();
|
||||
|
||||
const string& name() const { return name_; }
|
||||
|
||||
void dump(ostream&, unsigned) const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
NetProc*proc_;
|
||||
|
||||
private: // not implemented
|
||||
NetTaskDef(const NetTaskDef&);
|
||||
NetTaskDef& operator= (const NetTaskDef&);
|
||||
};
|
||||
|
||||
/*
|
||||
* A call to a user defined task is elaborated into this object. I
|
||||
* save the parameters and the pointer to the task definition.
|
||||
*/
|
||||
class NetUTask : public NetProc {
|
||||
|
||||
public:
|
||||
NetUTask(NetTaskDef*, const svector<NetExpr*>&);
|
||||
~NetUTask();
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -1193,6 +1232,10 @@ class Design {
|
|||
void add_memory(NetMemory*);
|
||||
NetMemory* find_memory(const string&name);
|
||||
|
||||
// Tasks
|
||||
void add_task(const string&n, NetTaskDef*);
|
||||
NetTaskDef* find_task(const string&key);
|
||||
|
||||
// NODES
|
||||
void add_node(NetNode*);
|
||||
void del_node(NetNode*);
|
||||
|
|
@ -1230,6 +1273,9 @@ class Design {
|
|||
|
||||
map<string,NetMemory*> memories_;
|
||||
|
||||
// List the task definitions in the design.
|
||||
map<string,NetTaskDef*> tasks_;
|
||||
|
||||
// List the nodes in the design
|
||||
NetNode*nodes_;
|
||||
|
||||
|
|
@ -1290,6 +1336,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
|
|||
|
||||
/*
|
||||
* $Log: netlist.h,v $
|
||||
* Revision 1.43 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.42 1999/06/24 04:24:18 steve
|
||||
* Handle expression widths for EEE and NEE operators,
|
||||
* add named blocks and scope handling,
|
||||
|
|
@ -1345,133 +1394,5 @@ extern ostream& operator << (ostream&, NetNet::Type);
|
|||
* memories as lvalues.
|
||||
*
|
||||
* Parse task declarations, integer types.
|
||||
*
|
||||
* Revision 1.28 1999/05/01 20:43:55 steve
|
||||
* Handle wide events, such as @(a) where a has
|
||||
* many bits in it.
|
||||
*
|
||||
* Add to vvm the binary ^ and unary & operators.
|
||||
*
|
||||
* Dump events a bit more completely.
|
||||
*
|
||||
* Revision 1.27 1999/05/01 02:57:53 steve
|
||||
* Handle much more complex event expressions.
|
||||
*
|
||||
* Revision 1.26 1999/04/25 22:52:32 steve
|
||||
* Generate SubSignal refrences in vvm.
|
||||
*
|
||||
* Revision 1.25 1999/04/25 00:44:10 steve
|
||||
* Core handles subsignal expressions.
|
||||
*
|
||||
* Revision 1.24 1999/04/22 04:56:58 steve
|
||||
* Add to vvm proceedural memory references.
|
||||
*
|
||||
* Revision 1.23 1999/04/19 01:59:36 steve
|
||||
* Add memories to the parse and elaboration phases.
|
||||
*
|
||||
* Revision 1.22 1999/03/15 02:43:32 steve
|
||||
* Support more operators, especially logical.
|
||||
*
|
||||
* Revision 1.21 1999/03/01 03:27:53 steve
|
||||
* Prevent the duplicate allocation of ESignal objects.
|
||||
*
|
||||
* Revision 1.20 1999/02/21 17:01:57 steve
|
||||
* Add support for module parameters.
|
||||
*
|
||||
* Revision 1.19 1999/02/15 02:06:15 steve
|
||||
* Elaborate gate ranges.
|
||||
*
|
||||
* Revision 1.18 1999/02/08 02:49:56 steve
|
||||
* Turn the NetESignal into a NetNode so
|
||||
* that it can connect to the netlist.
|
||||
* Implement the case statement.
|
||||
* Convince t-vvm to output code for
|
||||
* the case statement.
|
||||
*
|
||||
* Revision 1.17 1999/02/03 04:20:11 steve
|
||||
* Parse and elaborate the Verilog CASE statement.
|
||||
*
|
||||
* Revision 1.16 1999/02/01 00:26:49 steve
|
||||
* Carry some line info to the netlist,
|
||||
* Dump line numbers for processes.
|
||||
* Elaborate prints errors about port vector
|
||||
* width mismatch
|
||||
* Emit better handles null statements.
|
||||
*
|
||||
* Revision 1.15 1998/12/20 02:05:41 steve
|
||||
* Function to calculate wire initial value.
|
||||
*
|
||||
* Revision 1.14 1998/12/18 05:16:25 steve
|
||||
* Parse more UDP input edge descriptions.
|
||||
*
|
||||
* Revision 1.13 1998/12/17 23:54:58 steve
|
||||
* VVM support for small sequential UDP objects.
|
||||
*
|
||||
* Revision 1.12 1998/12/14 02:01:35 steve
|
||||
* Fully elaborate Sequential UDP behavior.
|
||||
*
|
||||
* Revision 1.11 1998/12/07 04:53:17 steve
|
||||
* Generate OBUF or IBUF attributes (and the gates
|
||||
* to garry them) where a wire is a pad. This involved
|
||||
* figuring out enough of the netlist to know when such
|
||||
* was needed, and to generate new gates and signales
|
||||
* to handle what's missing.
|
||||
*
|
||||
* Revision 1.10 1998/12/02 04:37:13 steve
|
||||
* Add the nobufz function to eliminate bufz objects,
|
||||
* Object links are marked with direction,
|
||||
* constant propagation is more careful will wide links,
|
||||
* Signal folding is aware of attributes, and
|
||||
* the XNF target can dump UDP objects based on LCA
|
||||
* attributes.
|
||||
*
|
||||
* Revision 1.9 1998/12/01 00:42:14 steve
|
||||
* Elaborate UDP devices,
|
||||
* Support UDP type attributes, and
|
||||
* pass those attributes to nodes that
|
||||
* are instantiated by elaboration,
|
||||
* Put modules into a map instead of
|
||||
* a simple list.
|
||||
*
|
||||
* Revision 1.8 1998/11/23 00:20:23 steve
|
||||
* NetAssign handles lvalues as pin links
|
||||
* instead of a signal pointer,
|
||||
* Wire attributes added,
|
||||
* Ability to parse UDP descriptions added,
|
||||
* XNF generates EXT records for signals with
|
||||
* the PAD attribute.
|
||||
*
|
||||
* Revision 1.7 1998/11/18 04:25:22 steve
|
||||
* Add -f flags for generic flag key/values.
|
||||
*
|
||||
* Revision 1.6 1998/11/16 05:03:53 steve
|
||||
* Add the sigfold function that unlinks excess
|
||||
* signal nodes, and add the XNF target.
|
||||
*
|
||||
* Revision 1.5 1998/11/13 06:23:17 steve
|
||||
* Introduce netlist optimizations with the
|
||||
* cprop function to do constant propogation.
|
||||
*
|
||||
* Revision 1.4 1998/11/09 18:55:34 steve
|
||||
* Add procedural while loops,
|
||||
* Parse procedural for loops,
|
||||
* Add procedural wait statements,
|
||||
* Add constant nodes,
|
||||
* Add XNOR logic gate,
|
||||
* Make vvm output look a bit prettier.
|
||||
*
|
||||
* Revision 1.3 1998/11/07 19:17:10 steve
|
||||
* Calculate expression widths at elaboration time.
|
||||
*
|
||||
* Revision 1.2 1998/11/07 17:05:05 steve
|
||||
* Handle procedural conditional, and some
|
||||
* of the conditional expressions.
|
||||
*
|
||||
* Elaborate signals and identifiers differently,
|
||||
* allowing the netlist to hold signal information.
|
||||
*
|
||||
* Revision 1.1 1998/11/03 23:29:01 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
|
|||
71
parse.y
71
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.47 1999/06/24 04:24:18 steve Exp $"
|
||||
#ident "$Id: parse.y,v 1.48 1999/07/03 02:12:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
|
|
@ -52,6 +52,8 @@ extern void lex_end_table();
|
|||
PGBuiltin::Type gatetype;
|
||||
NetNet::PortType porttype;
|
||||
|
||||
PTask*task;
|
||||
|
||||
PWire*wire;
|
||||
svector<PWire*>*wires;
|
||||
|
||||
|
|
@ -125,6 +127,7 @@ extern void lex_end_table();
|
|||
%type <gatetype> gatetype
|
||||
%type <porttype> port_type
|
||||
|
||||
%type <task> task_body
|
||||
%type <event_expr> event_expression
|
||||
%type <event_statement> event_control
|
||||
%type <statement> statement statement_opt
|
||||
|
|
@ -977,8 +980,16 @@ module_item
|
|||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
}
|
||||
| K_task IDENTIFIER ';' task_body K_endtask
|
||||
{ yyerror(@1, "Sorry, task declarations not supported.");
|
||||
| K_task IDENTIFIER ';'
|
||||
{ pform_push_scope(*$2); }
|
||||
task_body
|
||||
{ pform_pop_scope(); }
|
||||
K_endtask
|
||||
{ PTask*tmp = $5;
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
pform_set_task(*$2, $5);
|
||||
delete $2;
|
||||
}
|
||||
| K_function range_or_type_opt IDENTIFIER ';' func_body K_endfunction
|
||||
{ yyerror(@1, "Sorry, function declarations not supported.");
|
||||
|
|
@ -1454,25 +1465,52 @@ statement
|
|||
$$ = tmp;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER '(' expression_list ')' ';'
|
||||
{ $$ = pform_make_calltask($1, $3);
|
||||
{ PCallTask*tmp = new PCallTask(*$1, *$3);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
delete $1;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER '(' ')' ';'
|
||||
{ $$ = pform_make_calltask($1);
|
||||
{ svector<PExpr*>pt (0);
|
||||
PCallTask*tmp = new PCallTask(*$1, pt);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER ';'
|
||||
{ $$ = pform_make_calltask($1);
|
||||
{ svector<PExpr*>pt (0);
|
||||
PCallTask*tmp = new PCallTask(*$1, pt);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| identifier '(' expression_list ')' ';'
|
||||
{ yyerror(@1, "Sorry, task enabling not implemented.");
|
||||
$$ = new PNoop;
|
||||
{ PCallTask*tmp = new PCallTask(*$1, *$3);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
delete $1;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| identifier '(' ')' ';'
|
||||
{ yyerror(@1, "Sorry, task enabling not implemented.");
|
||||
$$ = new PNoop;
|
||||
{ svector<PExpr*>pt (0);
|
||||
PCallTask*tmp = new PCallTask(*$1, pt);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| identifier ';'
|
||||
{ yyerror(@1, "Sorry, task enabling not implemented.");
|
||||
$$ = new PNoop;
|
||||
{ svector<PExpr*>pt (0);
|
||||
PCallTask*tmp = new PCallTask(*$1, pt);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| error ';'
|
||||
{ yyerror(@1, "malformed statement");
|
||||
|
|
@ -1501,13 +1539,22 @@ statement_opt
|
|||
|
||||
task_body
|
||||
: task_item_list_opt statement_opt
|
||||
{ PTask*tmp = new PTask($2);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
task_item
|
||||
: block_item_decl
|
||||
| K_input range_opt list_of_variables ';'
|
||||
{ yyerror(@1, "Sorry, task input ports not implemented.");
|
||||
}
|
||||
| K_output range_opt list_of_variables ';'
|
||||
{ yyerror(@1, "Sorry, task output ports not implemented.");
|
||||
}
|
||||
| K_inout range_opt list_of_variables ';'
|
||||
{ yyerror(@1, "Sorry, task inout ports not implemented.");
|
||||
}
|
||||
;
|
||||
|
||||
task_item_list
|
||||
|
|
|
|||
58
pform.cc
58
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.30 1999/06/24 04:24:18 steve Exp $"
|
||||
#ident "$Id: pform.cc,v 1.31 1999/07/03 02:12:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "compiler.h"
|
||||
|
|
@ -37,7 +37,7 @@ string vl_file = "";
|
|||
|
||||
extern int VLparse();
|
||||
|
||||
static Module*cur_module = 0;
|
||||
static Module*pform_cur_module = 0;
|
||||
|
||||
/*
|
||||
* The scope stack and the following functions handle the processing
|
||||
|
|
@ -96,13 +96,13 @@ static unsigned long evaluate_delay(PExpr*delay)
|
|||
|
||||
void pform_startmodule(const string&name, svector<PWire*>*ports)
|
||||
{
|
||||
assert( cur_module == 0 );
|
||||
cur_module = new Module(name, ports? ports->count() : 0);
|
||||
assert( pform_cur_module == 0 );
|
||||
pform_cur_module = new Module(name, ports? ports->count() : 0);
|
||||
|
||||
if (ports) {
|
||||
for (unsigned idx = 0 ; idx < ports->count() ; idx += 1) {
|
||||
cur_module->add_wire((*ports)[idx]);
|
||||
cur_module->ports[idx] = (*ports)[idx];
|
||||
pform_cur_module->add_wire((*ports)[idx]);
|
||||
pform_cur_module->ports[idx] = (*ports)[idx];
|
||||
}
|
||||
delete ports;
|
||||
}
|
||||
|
|
@ -110,15 +110,15 @@ void pform_startmodule(const string&name, svector<PWire*>*ports)
|
|||
|
||||
void pform_endmodule(const string&name)
|
||||
{
|
||||
assert(cur_module);
|
||||
assert(name == cur_module->get_name());
|
||||
vl_modules[name] = cur_module;
|
||||
cur_module = 0;
|
||||
assert(pform_cur_module);
|
||||
assert(name == pform_cur_module->get_name());
|
||||
vl_modules[name] = pform_cur_module;
|
||||
pform_cur_module = 0;
|
||||
}
|
||||
|
||||
bool pform_expression_is_constant(const PExpr*ex)
|
||||
{
|
||||
return ex->is_constant(cur_module);
|
||||
return ex->is_constant(pform_cur_module);
|
||||
}
|
||||
|
||||
void pform_make_udp(string*name, list<string>*parms,
|
||||
|
|
@ -285,7 +285,7 @@ void pform_makegate(PGBuiltin::Type type,
|
|||
cur->set_file(info.file);
|
||||
cur->set_lineno(info.lineno);
|
||||
|
||||
cur_module->add_gate(cur);
|
||||
pform_cur_module->add_gate(cur);
|
||||
}
|
||||
|
||||
void pform_makegates(PGBuiltin::Type type,
|
||||
|
|
@ -320,7 +320,7 @@ static void pform_make_modgate(const string&type,
|
|||
PGate*cur = new PGModule(type, name, wires);
|
||||
cur->set_file(fn);
|
||||
cur->set_lineno(ln);
|
||||
cur_module->add_gate(cur);
|
||||
pform_cur_module->add_gate(cur);
|
||||
}
|
||||
|
||||
static void pform_make_modgate(const string&type,
|
||||
|
|
@ -346,7 +346,7 @@ static void pform_make_modgate(const string&type,
|
|||
PGate*cur = new PGModule(type, name, pins, npins);
|
||||
cur->set_file(fn);
|
||||
cur->set_lineno(ln);
|
||||
cur_module->add_gate(cur);
|
||||
pform_cur_module->add_gate(cur);
|
||||
}
|
||||
|
||||
void pform_make_modgates(const string&type, svector<lgate>*gates)
|
||||
|
|
@ -377,7 +377,7 @@ PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval)
|
|||
(*wires)[0] = lval;
|
||||
(*wires)[1] = rval;
|
||||
PGAssign*cur = new PGAssign(wires);
|
||||
cur_module->add_gate(cur);
|
||||
pform_cur_module->add_gate(cur);
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
|
@ -385,7 +385,7 @@ void pform_makewire(const vlltype&li, const string&nm,
|
|||
NetNet::Type type)
|
||||
{
|
||||
const string name = scoped_name(nm);
|
||||
PWire*cur = cur_module->get_wire(name);
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
if (cur) {
|
||||
if (cur->get_wire_type() != NetNet::IMPLICIT) {
|
||||
strstream msg;
|
||||
|
|
@ -402,7 +402,7 @@ void pform_makewire(const vlltype&li, const string&nm,
|
|||
cur = new PWire(name, type, NetNet::NOT_A_PORT);
|
||||
cur->set_file(li.text);
|
||||
cur->set_lineno(li.first_line);
|
||||
cur_module->add_wire(cur);
|
||||
pform_cur_module->add_wire(cur);
|
||||
}
|
||||
|
||||
void pform_makewire(const vlltype&li, const list<string>*names,
|
||||
|
|
@ -417,7 +417,7 @@ void pform_makewire(const vlltype&li, const list<string>*names,
|
|||
|
||||
void pform_set_port_type(const string&name, NetNet::PortType pt)
|
||||
{
|
||||
PWire*cur = cur_module->get_wire(name);
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
if (cur == 0) {
|
||||
VLerror("name is not a port.");
|
||||
return;
|
||||
|
|
@ -427,9 +427,14 @@ void pform_set_port_type(const string&name, NetNet::PortType pt)
|
|||
VLerror("error setting port direction.");
|
||||
}
|
||||
|
||||
void pform_set_task(const string&name, PTask*task)
|
||||
{
|
||||
pform_cur_module->add_task(name, task);
|
||||
}
|
||||
|
||||
void pform_set_attrib(const string&name, const string&key, const string&value)
|
||||
{
|
||||
PWire*cur = cur_module->get_wire(name);
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
assert(cur);
|
||||
cur->attributes[key] = value;
|
||||
}
|
||||
|
|
@ -456,7 +461,7 @@ void pform_set_type_attrib(const string&name, const string&key,
|
|||
*/
|
||||
void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r)
|
||||
{
|
||||
PWire*cur = cur_module->get_wire(name);
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
if (cur == 0) {
|
||||
VLerror("name is not a valid net.");
|
||||
return;
|
||||
|
|
@ -470,7 +475,7 @@ static void pform_set_net_range(const string&name, const svector<PExpr*>*range)
|
|||
assert(range);
|
||||
assert(range->count() == 2);
|
||||
|
||||
PWire*cur = cur_module->get_wire(name);
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
if (cur == 0) {
|
||||
VLerror("name is not a valid net.");
|
||||
return;
|
||||
|
|
@ -494,7 +499,7 @@ void pform_set_net_range(list<string>*names, const svector<PExpr*>*range)
|
|||
|
||||
void pform_set_parameter(const string&name, PExpr*expr)
|
||||
{
|
||||
cur_module->parameters[name] = expr;
|
||||
pform_cur_module->parameters[name] = expr;
|
||||
}
|
||||
|
||||
void pform_set_port_type(list<string>*names, NetNet::PortType pt)
|
||||
|
|
@ -508,7 +513,7 @@ void pform_set_port_type(list<string>*names, NetNet::PortType pt)
|
|||
|
||||
static void pform_set_reg_integer(const string&name)
|
||||
{
|
||||
PWire*cur = cur_module->get_wire(name);
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
assert(cur);
|
||||
bool rc = cur->set_wire_type(NetNet::INTEGER);
|
||||
assert(rc);
|
||||
|
|
@ -546,10 +551,11 @@ svector<PWire*>* pform_make_udp_input_ports(list<string>*names)
|
|||
PProcess* pform_make_behavior(PProcess::Type type, Statement*st)
|
||||
{
|
||||
PProcess*pp = new PProcess(type, st);
|
||||
cur_module->add_behavior(pp);
|
||||
pform_cur_module->add_behavior(pp);
|
||||
return pp;
|
||||
}
|
||||
|
||||
#if 0
|
||||
Statement* pform_make_calltask(string*name, svector<PExpr*>*parms)
|
||||
{
|
||||
if (parms == 0)
|
||||
|
|
@ -560,6 +566,7 @@ Statement* pform_make_calltask(string*name, svector<PExpr*>*parms)
|
|||
delete parms;
|
||||
return ct;
|
||||
}
|
||||
#endif
|
||||
|
||||
FILE*vl_input = 0;
|
||||
int pform_parse(const char*path, map<string,Module*>&modules,
|
||||
|
|
@ -587,6 +594,9 @@ int pform_parse(const char*path, map<string,Module*>&modules,
|
|||
|
||||
/*
|
||||
* $Log: pform.cc,v $
|
||||
* Revision 1.31 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.30 1999/06/24 04:24:18 steve
|
||||
* Handle expression widths for EEE and NEE operators,
|
||||
* add named blocks and scope handling,
|
||||
|
|
|
|||
8
pform.h
8
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.21 1999/06/24 04:24:18 steve Exp $"
|
||||
#ident "$Id: pform.h,v 1.22 1999/07/03 02:12:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
# include "Statement.h"
|
||||
# include "PGate.h"
|
||||
# include "PExpr.h"
|
||||
# include "PTask.h"
|
||||
# include "PUdp.h"
|
||||
# include "PWire.h"
|
||||
# include "verinum.h"
|
||||
|
|
@ -119,13 +120,13 @@ extern void pform_set_port_type(list<string>*names, NetNet::PortType);
|
|||
extern void pform_set_net_range(list<string>*names, const svector<PExpr*>*);
|
||||
extern void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r);
|
||||
extern void pform_set_reg_integer(list<string>*names);
|
||||
extern void pform_set_task(const string&, PTask*);
|
||||
extern void pform_set_attrib(const string&name, const string&key,
|
||||
const string&value);
|
||||
extern void pform_set_type_attrib(const string&name, const string&key,
|
||||
const string&value);
|
||||
extern void pform_set_parameter(const string&name, PExpr*expr);
|
||||
extern PProcess* pform_make_behavior(PProcess::Type, Statement*);
|
||||
extern Statement* pform_make_calltask(string*t, svector<PExpr*>* =0);
|
||||
|
||||
extern svector<PWire*>* pform_make_udp_input_ports(list<string>*);
|
||||
|
||||
|
|
@ -156,6 +157,9 @@ extern void pform_dump(ostream&out, Module*mod);
|
|||
|
||||
/*
|
||||
* $Log: pform.h,v $
|
||||
* Revision 1.22 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.21 1999/06/24 04:24:18 steve
|
||||
* Handle expression widths for EEE and NEE operators,
|
||||
* add named blocks and scope handling,
|
||||
|
|
|
|||
|
|
@ -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.25 1999/06/24 04:24:18 steve Exp $"
|
||||
#ident "$Id: pform_dump.cc,v 1.26 1999/07/03 02:12:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -304,7 +304,7 @@ void PCallTask::dump(ostream&out, unsigned ind) const
|
|||
out << ")";
|
||||
}
|
||||
|
||||
out << ";" << endl;
|
||||
out << "; /* " << get_line() << " */" << endl;
|
||||
}
|
||||
|
||||
void PCase::dump(ostream&out, unsigned ind) const
|
||||
|
|
@ -398,6 +398,12 @@ void PRepeat::dump(ostream&out, unsigned ind) const
|
|||
statement_->dump(out, ind+3);
|
||||
}
|
||||
|
||||
void PTask::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
statement_->dump(out, ind);
|
||||
}
|
||||
|
||||
|
||||
void PWhile::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "while (" << *cond_ << ")" << endl;
|
||||
|
|
@ -420,40 +426,46 @@ void PProcess::dump(ostream&out, unsigned ind) const
|
|||
statement_->dump(out, ind+2);
|
||||
}
|
||||
|
||||
void pform_dump(ostream&out, Module*mod)
|
||||
void Module::dump(ostream&out) const
|
||||
{
|
||||
out << "module " << mod->get_name() << ";" << endl;
|
||||
out << "module " << name_ << ";" << endl;
|
||||
|
||||
typedef map<string,PExpr*>::const_iterator parm_iter_t;
|
||||
for (parm_iter_t cur = mod->parameters.begin()
|
||||
; cur != mod->parameters.end() ; cur ++) {
|
||||
for (parm_iter_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
out << " parameter " << (*cur).first << " = " <<
|
||||
*(*cur).second << ";" << endl;
|
||||
}
|
||||
|
||||
// Iterate through and display all the wires.
|
||||
const list<PWire*>&wires = mod->get_wires();
|
||||
for (list<PWire*>::const_iterator wire = wires.begin()
|
||||
; wire != wires.end()
|
||||
for (list<PWire*>::const_iterator wire = wires_.begin()
|
||||
; wire != wires_.end()
|
||||
; wire ++ ) {
|
||||
|
||||
(*wire)->dump(out);
|
||||
}
|
||||
|
||||
// Dump the task definitions.
|
||||
typedef map<string,PTask*>::const_iterator task_iter_t;
|
||||
for (task_iter_t cur = tasks_.begin()
|
||||
; cur != tasks_.end() ; cur ++) {
|
||||
out << " task " << (*cur).first << ";" << endl;
|
||||
(*cur).second->dump(out, 6);
|
||||
out << " endtask;" << endl;
|
||||
}
|
||||
|
||||
|
||||
// Iterate through and display all the gates
|
||||
const list<PGate*>&gates = mod->get_gates();
|
||||
for (list<PGate*>::const_iterator gate = gates.begin()
|
||||
; gate != gates.end()
|
||||
for (list<PGate*>::const_iterator gate = gates_.begin()
|
||||
; gate != gates_.end()
|
||||
; gate ++ ) {
|
||||
|
||||
(*gate)->dump(out);
|
||||
}
|
||||
|
||||
|
||||
const list<PProcess*>&behaves = mod->get_behaviors();
|
||||
for (list<PProcess*>::const_iterator behav = behaves.begin()
|
||||
; behav != behaves.end()
|
||||
for (list<PProcess*>::const_iterator behav = behaviors_.begin()
|
||||
; behav != behaviors_.end()
|
||||
; behav ++ ) {
|
||||
|
||||
(*behav)->dump(out, 4);
|
||||
|
|
@ -462,6 +474,11 @@ void pform_dump(ostream&out, Module*mod)
|
|||
out << "endmodule" << endl;
|
||||
}
|
||||
|
||||
void pform_dump(ostream&out, Module*mod)
|
||||
{
|
||||
mod->dump(out);
|
||||
}
|
||||
|
||||
void PUdp::dump(ostream&out) const
|
||||
{
|
||||
out << "primitive " << name_ << "(" << ports[0];
|
||||
|
|
@ -504,6 +521,9 @@ void PUdp::dump(ostream&out) const
|
|||
|
||||
/*
|
||||
* $Log: pform_dump.cc,v $
|
||||
* Revision 1.26 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.25 1999/06/24 04:24:18 steve
|
||||
* Handle expression widths for EEE and NEE operators,
|
||||
* add named blocks and scope handling,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: t-null.cc,v 1.3 1999/06/19 21:06:16 steve Exp $"
|
||||
#ident "$Id: t-null.cc,v 1.4 1999/07/03 02:12:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
|
@ -31,8 +31,11 @@ static class target_null_t : public target_t {
|
|||
|
||||
public:
|
||||
void bufz(ostream&os, const NetBUFZ*) { }
|
||||
void memory(ostream&, const NetMemory*) { }
|
||||
void task_def(ostream&, const NetTaskDef*) { }
|
||||
void net_esignal(ostream&, const NetESignal*) { }
|
||||
void net_event(ostream&, const NetNEvent*) { }
|
||||
void proc_block(ostream&, const NetBlock*) { }
|
||||
void proc_delay(ostream&, const NetPDelay*) { }
|
||||
void proc_event(ostream&, const NetPEvent*) { }
|
||||
void proc_forever(ostream&, const NetForever*) { }
|
||||
|
|
@ -43,6 +46,9 @@ static class target_null_t : public target_t {
|
|||
extern const struct target tgt_null = { "null", &target_null_obj };
|
||||
/*
|
||||
* $Log: t-null.cc,v $
|
||||
* Revision 1.4 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.3 1999/06/19 21:06:16 steve
|
||||
* Elaborate and supprort to vvm the forever
|
||||
* and repeat statements.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: t-verilog.cc,v 1.5 1999/06/13 16:30:06 steve Exp $"
|
||||
#ident "$Id: t-verilog.cc,v 1.6 1999/07/03 02:12:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -46,7 +46,7 @@ class target_verilog : public target_t {
|
|||
virtual void proc_block(ostream&os, const NetBlock*);
|
||||
virtual void proc_delay(ostream&os, const NetPDelay*);
|
||||
virtual void proc_event(ostream&os, const NetPEvent*);
|
||||
virtual void proc_task(ostream&os, const NetTask*);
|
||||
virtual void proc_stask(ostream&os, const NetSTask*);
|
||||
virtual void end_design(ostream&os, const Design*);
|
||||
private:
|
||||
unsigned indent_;
|
||||
|
|
@ -236,7 +236,7 @@ static void vtask_parm(ostream&os, const NetExpr*ex)
|
|||
}
|
||||
}
|
||||
|
||||
void target_verilog::proc_task(ostream&os, const NetTask*net)
|
||||
void target_verilog::proc_stask(ostream&os, const NetSTask*net)
|
||||
{
|
||||
os << setw(indent_) << "" << net->name();
|
||||
if (net->nparms() > 0) {
|
||||
|
|
@ -271,6 +271,9 @@ const struct target tgt_verilog = {
|
|||
|
||||
/*
|
||||
* $Log: t-verilog.cc,v $
|
||||
* Revision 1.6 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.5 1999/06/13 16:30:06 steve
|
||||
* Unify the NetAssign constructors a bit.
|
||||
*
|
||||
|
|
|
|||
40
t-vvm.cc
40
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.26 1999/06/24 04:21:45 steve Exp $"
|
||||
#ident "$Id: t-vvm.cc,v 1.27 1999/07/03 02:12:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <iostream>
|
||||
|
|
@ -58,7 +58,7 @@ class target_vvm : public target_t {
|
|||
virtual void proc_condit(ostream&os, const NetCondit*);
|
||||
virtual void proc_forever(ostream&os, const NetForever*);
|
||||
virtual void proc_repeat(ostream&os, const NetRepeat*);
|
||||
virtual void proc_task(ostream&os, const NetTask*);
|
||||
virtual void proc_stask(ostream&os, const NetSTask*);
|
||||
virtual void proc_while(ostream&os, const NetWhile*);
|
||||
virtual void proc_event(ostream&os, const NetPEvent*);
|
||||
virtual void proc_delay(ostream&os, const NetPDelay*);
|
||||
|
|
@ -1038,23 +1038,24 @@ void target_vvm::proc_repeat(ostream&os, const NetRepeat*net)
|
|||
os << " {" << endl;
|
||||
}
|
||||
|
||||
void target_vvm::proc_task(ostream&os, const NetTask*net)
|
||||
/*
|
||||
* Calls to system tasks are done here. We know that this is a system
|
||||
* task and that I need to generate an external call. Calls to user
|
||||
* defined tasks are handled elsewhere.
|
||||
*/
|
||||
void target_vvm::proc_stask(ostream&os, const NetSTask*net)
|
||||
{
|
||||
if (net->name()[0] == '$') {
|
||||
string ptmp = make_temp();
|
||||
os << " struct vvm_calltf_parm " << 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 << " " << ptmp << "[" << idx << "] = " <<
|
||||
val << ";" << endl;
|
||||
}
|
||||
os << " vvm_calltask(sim_, \"" << net->name() << "\", " <<
|
||||
net->nparms() << ", " << ptmp << ");" << endl;
|
||||
} else {
|
||||
os << " // Huh? " << net->name() << endl;
|
||||
}
|
||||
string ptmp = make_temp();
|
||||
os << " struct vvm_calltf_parm " << 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 << " " << ptmp << "[" << idx << "] = " <<
|
||||
val << ";" << endl;
|
||||
}
|
||||
os << " vvm_calltask(sim_, \"" << net->name() << "\", " <<
|
||||
net->nparms() << ", " << ptmp << ");" << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1201,6 +1202,9 @@ extern const struct target tgt_vvm = {
|
|||
};
|
||||
/*
|
||||
* $Log: t-vvm.cc,v $
|
||||
* Revision 1.27 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.26 1999/06/24 04:21:45 steve
|
||||
* Add the === and !== binary operators.
|
||||
*
|
||||
|
|
|
|||
23
target.cc
23
target.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: target.cc,v 1.12 1999/06/19 21:06:16 steve Exp $"
|
||||
#ident "$Id: target.cc,v 1.13 1999/07/03 02:12:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "target.h"
|
||||
|
|
@ -41,6 +41,12 @@ void target_t::memory(ostream&os, const NetMemory*)
|
|||
"Unhandled memory." << endl;
|
||||
}
|
||||
|
||||
void target_t::task_def(ostream&os, const NetTaskDef*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled task definition." << endl;
|
||||
}
|
||||
|
||||
void target_t::logic(ostream&os, const NetLogic*)
|
||||
{
|
||||
}
|
||||
|
|
@ -107,6 +113,8 @@ void target_t::proc_assign_nb(ostream&os, const NetAssignNB*)
|
|||
|
||||
void target_t::proc_block(ostream&os, const NetBlock*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_block." << endl;
|
||||
}
|
||||
|
||||
void target_t::proc_case(ostream&os, const NetCase*cur)
|
||||
|
|
@ -147,8 +155,16 @@ void target_t::proc_repeat(ostream&os, const NetRepeat*)
|
|||
"Unhandled proc_repeat." << endl;
|
||||
}
|
||||
|
||||
void target_t::proc_task(ostream&os, const NetTask*)
|
||||
void target_t::proc_stask(ostream&os, const NetSTask*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_stask." << endl;
|
||||
}
|
||||
|
||||
void target_t::proc_utask(ostream&os, const NetUTask*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_utask." << endl;
|
||||
}
|
||||
|
||||
void target_t::proc_while(ostream&os, const NetWhile*net)
|
||||
|
|
@ -220,6 +236,9 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
|
|||
|
||||
/*
|
||||
* $Log: target.cc,v $
|
||||
* Revision 1.13 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.12 1999/06/19 21:06:16 steve
|
||||
* Elaborate and supprort to vvm the forever
|
||||
* and repeat statements.
|
||||
|
|
|
|||
11
target.h
11
target.h
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: target.h,v 1.12 1999/06/19 21:06:16 steve Exp $"
|
||||
#ident "$Id: target.h,v 1.13 1999/07/03 02:12:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
|
@ -61,6 +61,9 @@ struct target_t {
|
|||
/* Output a memory (called for each memory object) */
|
||||
virtual void memory(ostream&os, const NetMemory*);
|
||||
|
||||
/* Output a defined task. */
|
||||
virtual void task_def(ostream&, const NetTaskDef*);
|
||||
|
||||
/* Output a gate (called for each gate) */
|
||||
virtual void logic(ostream&os, const NetLogic*);
|
||||
virtual void bufz(ostream&os, const NetBUFZ*);
|
||||
|
|
@ -83,7 +86,8 @@ struct target_t {
|
|||
virtual void proc_condit(ostream&os, const NetCondit*);
|
||||
virtual void proc_forever(ostream&os, const NetForever*);
|
||||
virtual void proc_repeat(ostream&os, const NetRepeat*);
|
||||
virtual void proc_task(ostream&os, const NetTask*);
|
||||
virtual void proc_stask(ostream&os, const NetSTask*);
|
||||
virtual void proc_utask(ostream&os, const NetUTask*);
|
||||
virtual void proc_while(ostream&os, const NetWhile*);
|
||||
|
||||
virtual void proc_event(ostream&os, const NetPEvent*);
|
||||
|
|
@ -127,6 +131,9 @@ extern const struct target *target_table[];
|
|||
|
||||
/*
|
||||
* $Log: target.h,v $
|
||||
* Revision 1.13 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
* Revision 1.12 1999/06/19 21:06:16 steve
|
||||
* Elaborate and supprort to vvm the forever
|
||||
* and repeat statements.
|
||||
|
|
|
|||
Loading…
Reference in New Issue