Elaborate class task and function methods.

The parse of class methods already works, this patch forms
the methods into their own scopes, and elaborates those scopes.
The "this"
This commit is contained in:
Stephen Williams 2013-03-14 20:08:32 -07:00
parent fac5cbca43
commit 17330a3073
22 changed files with 605 additions and 180 deletions

View File

@ -372,6 +372,7 @@ class PEIdent : public PExpr {
std::list<long>&prefix_indices) const;
private:
NetAssign_*elaborate_lval_method_class_member_(Design*, NetScope*) const;
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const;
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const;
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
@ -449,6 +450,11 @@ class PEIdent : public PExpr {
NetScope*found,
bool need_const) const;
NetExpr*elaborate_expr_class_member_(Design*des,
NetScope*scope,
unsigned expr_wid,
unsigned flags) const;
private:
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
bool bidirectional_flag) const;

View File

@ -22,7 +22,7 @@
# include <cassert>
PFunction::PFunction(perm_string name, LexicalScope*parent, bool is_auto__)
: PTaskFunc(name, parent), ports_(0), statement_(0)
: PTaskFunc(name, parent), statement_(0)
{
is_auto_ = is_auto__;
return_type_.type = PTF_NONE;
@ -32,12 +32,6 @@ PFunction::~PFunction()
{
}
void PFunction::set_ports(vector<PWire *>*p)
{
assert(ports_ == 0);
ports_ = p;
}
void PFunction::set_statement(Statement*s)
{
assert(s != 0);

View File

@ -22,7 +22,7 @@
# include <cassert>
PTaskFunc::PTaskFunc(perm_string n, LexicalScope*p)
: PScope(n,p), this_type_(0)
: PScope(n,p), this_type_(0), ports_(0)
{
}
@ -30,14 +30,31 @@ PTaskFunc::~PTaskFunc()
{
}
void PTaskFunc::set_this(class_type_t*type)
void PTaskFunc::set_ports(vector<PWire*>*p)
{
assert(ports_ == 0);
ports_ = p;
}
void PTaskFunc::set_this(class_type_t*type, PWire*this_wire)
{
assert(this_type_ == 0);
this_type_ = type;
// Push a synthetis argument that is the "this" value.
if (ports_==0)
ports_ = new vector<PWire*>;
size_t use_size = ports_->size();
ports_->resize(use_size + 1);
for (size_t idx = use_size ; idx > 0 ; idx -= 1)
ports_->at(idx) = ports_->at(idx-1);
ports_->at(0) = this_wire;
}
PTask::PTask(perm_string name, LexicalScope*parent, bool is_auto__)
: PTaskFunc(name, parent), ports_(0), statement_(0)
: PTaskFunc(name, parent), statement_(0)
{
is_auto_ = is_auto__;
}
@ -46,12 +63,6 @@ PTask::~PTask()
{
}
void PTask::set_ports(vector<PWire*>*p)
{
assert(ports_ == 0);
ports_ = p;
}
void PTask::set_statement(Statement*s)
{
assert(statement_ == 0);

16
PTask.h
View File

@ -26,6 +26,7 @@
# include <vector>
# include <list>
class Design;
class NetNet;
class NetScope;
class PWire;
class Statement;
@ -56,14 +57,23 @@ class PTaskFunc : public PScope, public LineInfo {
PTaskFunc(perm_string name, LexicalScope*parent);
~PTaskFunc();
void set_this(class_type_t*use_type);
void set_ports(std::vector<PWire *>*p);
void set_this(class_type_t*use_type, PWire*this_wire);
// If this task is a method of a class, this returns a pointer
// to the class type.
inline class_type_t* method_of() const { return this_type_; }
protected:
void elaborate_sig_ports_(Design*des, NetScope*scope,
std::vector<NetNet*>&ports) const;
void dump_ports_(std::ostream&out, unsigned ind) const;
private:
class_type_t*this_type_;
std::vector<PWire*>*ports_;
};
/*
@ -75,7 +85,6 @@ class PTask : public PTaskFunc {
explicit PTask(perm_string name, LexicalScope*parent, bool is_auto);
~PTask();
void set_ports(std::vector<PWire *>*p);
void set_statement(Statement *s);
// Tasks introduce scope, to need to be handled during the
@ -95,7 +104,6 @@ class PTask : public PTaskFunc {
void dump(ostream&, unsigned) const;
private:
std::vector<PWire*>*ports_;
Statement*statement_;
bool is_auto_;
@ -117,7 +125,6 @@ class PFunction : public PTaskFunc {
explicit PFunction(perm_string name, LexicalScope*parent, bool is_auto);
~PFunction();
void set_ports(std::vector<PWire *>*p);
void set_statement(Statement *s);
void set_return(PTaskFuncArg t);
@ -135,7 +142,6 @@ class PFunction : public PTaskFunc {
private:
PTaskFuncArg return_type_;
std::vector<PWire *> *ports_;
Statement *statement_;
bool is_auto_;
};

View File

@ -28,6 +28,7 @@
# include "netlist.h"
# include "compiler.h"
# include "discipline.h"
# include "netclass.h"
# include "netdarray.h"
# include "netvector.h"
# include "ivl_assert.h"
@ -747,7 +748,7 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "task " << scope_path(scope_) << ";" << endl;
for (unsigned idx = 0 ; idx < ports_.count() ; idx += 1) {
for (unsigned idx = 0 ; idx < ports_.size() ; idx += 1) {
o << setw(ind+4) << "";
assert(ports_[idx]);
switch (ports_[idx]->port_type()) {
@ -767,7 +768,10 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const
o << ports_[idx]->name() << ";" << endl;
}
proc_->dump(o, ind+4);
if (proc_)
proc_->dump(o, ind+4);
else
o << setw(ind+4) << "" << "MISSING PROCEDURAL CODE" << endl;
o << setw(ind) << "" << "endtask" << endl;
}
@ -1140,7 +1144,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const
if (statement_)
statement_->dump(o, ind+2);
else
o << setw(ind+2) << "" << "// NO STATEMENT" << endl;
o << setw(ind+2) << "" << "MISSING PROCEDURAL CODE" << endl;
}
void NetPDelay::dump(ostream&o, unsigned ind) const
@ -1173,6 +1177,11 @@ void NetRepeat::dump(ostream&o, unsigned ind) const
statement_->dump(o, ind+2);
}
void netclass_t::dump_scope(ostream&fd) const
{
class_scope_->dump(fd);
}
void NetScope::dump(ostream&o) const
{
/* This is a constructed hierarchical name. */
@ -1320,6 +1329,11 @@ void NetScope::dump(ostream&o) const
for (map<hname_t,NetScope*>::const_iterator cur = children_.begin()
; cur != children_.end() ; ++ cur )
cur->second->dump(o);
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
; cur != classes_.end() ; ++ cur ) {
cur->second->dump_scope(o);
}
}
void NetSTask::dump(ostream&o, unsigned ind) const
@ -1588,7 +1602,7 @@ void NetETernary::dump(ostream&o) const
void NetEUFunc::dump(ostream&o) const
{
o << func_->basename() << "(";
o << scope_path(func_) << "(";
if (! parms_.empty()) {
parms_[0]->dump(o);
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {

View File

@ -1163,6 +1163,30 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
return expr_width_;
}
if (netclass_t*class_type = net->class_type()) {
cerr << get_fileline() << ": PECallFunction::test_width_method_: "
<< "Try to find method " << method_name
<< " of class " << class_type->get_name() << endl;
NetScope*func = class_type->method_from_name(method_name);
if (func == 0) {
return 0;
}
// Get the function result size be getting the details
// from the variable in the function scope that has the
// name of the function.
if (NetNet*res = func->find_signal(method_name)) {
expr_type_ = res->data_type();
expr_width_= res->vector_width();
min_width_ = expr_width_;
signed_flag_ = res->get_signed();
return expr_width_;
} else {
ivl_assert(*this, 0);
}
}
return 0;
}
@ -1991,6 +2015,25 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
}
}
if (netclass_t*class_type = net->class_type()) {
NetScope*func = class_type->method_from_name(method_name);
if (func == 0) {
return 0;
}
NetNet*res = func->find_signal(func->basename());
ivl_assert(*this, res);
vector<NetExpr*>parms;
cerr << get_fileline() << ": PECallFunction::elaborate_expr_method_: "
<< "Stub arguments to the function method." << endl;
NetESignal*eres = new NetESignal(res);
NetEUFunc*call = new NetEUFunc(scope, func, eres, parms, false);
call->set_line(*this);
return call;
}
return 0;
}
@ -2699,6 +2742,51 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
return tmp;
}
/*
* Guess that the path_ is the name of a member of a containing class,
* and see how that works. If it turns out that the current scope is
* not a method, or the name is not in the parent class, then
* fail. Otherwise, return a NetEProperty.
*/
NetExpr* PEIdent::elaborate_expr_class_member_(Design*, NetScope*scope,
unsigned, unsigned) const
{
if (!gn_system_verilog())
return 0;
if (scope->parent() == 0)
return 0;
if (path_.size() != 1)
return 0;
const netclass_t*class_type = scope->parent()->class_def();
if (class_type == 0)
return 0;
perm_string member_name = peek_tail_name(path_);
int pidx = class_type->property_idx_from_name(member_name);
if (pidx < 0)
return 0;
NetNet*this_net = scope->find_signal(perm_string::literal("@"));
if (this_net == 0) {
cerr << get_fileline() << ": internal error: "
<< "Unable to find 'this' port of " << scope_path(scope)
<< "." << endl;
return 0;
}
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member: "
<< "Found member " << member_name
<< " is a member of class " << class_type->get_name()
<< ", so synthesizing a NetEProperty." << endl;
}
NetEProperty*tmp = new NetEProperty(this_net, member_name);
tmp->set_line(*this);
return tmp;
}
/*
* Elaborate an identifier in an expression. The identifier can be a
* parameter name, a signal name or a memory name. It can also be a
@ -2721,6 +2809,17 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
const NetExpr*ex1, *ex2;
// Special case: Detect the special situation that this name
// is the name of a variable in the class, and this is a class
// method. We sense that this might be the case by noting that
// the parent scope of where we are working is a
// NetScope::CLASS, the path_ is a single component, and the
// name is a property of the class. If that turns out to be
// the case, then handle this specially.
if (NetExpr*tmp = elaborate_expr_class_member_(des, scope, expr_wid, flags)) {
return tmp;
}
if (path_.size() > 1) {
if (NEED_CONST & flags) {
cerr << get_fileline() << ": error: A hierarchical reference"

View File

@ -158,6 +158,11 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
NetEvent* eve = 0;
perm_string method_name;
/* Try to detect the special case that we are in a method and
the identifier is a member of the class. */
if (NetAssign_*tmp = elaborate_lval_method_class_member_(des, scope))
return tmp;
symbol_search(this, des, scope, path_, reg, par, eve);
/* If the signal is not found, check to see if this is a
@ -296,6 +301,39 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
return lv;
}
NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
NetScope*scope) const
{
if (!gn_system_verilog())
return 0;
if (scope->parent() == 0)
return 0;
if (path_.size() != 1)
return 0;
const netclass_t*class_type = scope->parent()->class_def();
if (class_type == 0)
return 0;
perm_string member_name = peek_tail_name(path_);
int pidx = class_type->property_idx_from_name(member_name);
if (pidx < 0)
return 0;
NetNet*this_net = scope->find_signal(perm_string::literal("@"));
if (this_net == 0) {
cerr << get_fileline() << ": internal error: "
<< "Unable to find 'this' port of " << scope_path(scope)
<< "." << endl;
return 0;
}
NetAssign_*this_lval = new NetAssign_(this_net);
this_lval->set_property(member_name);
return this_lval;
}
NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
NetScope*scope,
NetNet*reg) const

View File

@ -296,6 +296,18 @@ static void elaborate_scope_class(Design*des, NetScope*scope,
class_type_t*use_type = pclass->type;
netclass_t*use_class = new netclass_t(use_type->name);
if (debug_scopes) {
cerr << pclass->get_fileline() <<": debug: "
<< "Elaborate scope class " << pclass->pscope_name() << endl;
}
// Class scopes have no parent scope, because references are
// not allowed to escape a class method.
NetScope*class_scope = new NetScope(0, hname_t(pclass->pscope_name()),
NetScope::CLASS);
class_scope->set_class_def(use_class);
use_class->set_class_scope(class_scope);
for (map<perm_string, data_type_t*>::iterator cur = use_type->properties.begin()
; cur != use_type->properties.end() ; ++ cur) {
ivl_type_s*tmp = cur->second->elaborate_type(des, scope);
@ -304,14 +316,38 @@ static void elaborate_scope_class(Design*des, NetScope*scope,
for (map<perm_string,PTask*>::iterator cur = pclass->tasks.begin()
; cur != pclass->tasks.end() ; ++cur) {
cerr << cur->second->get_fileline() << ": sorry: "
<< "Class methods (tasks) not supported." << endl;
hname_t use_name (cur->first);
NetScope*method_scope = new NetScope(class_scope, use_name, NetScope::TASK);
// Task methods are always automatic...
method_scope->is_auto(true);
method_scope->set_line(cur->second);
if (debug_scopes) {
cerr << cur->second->get_fileline() << ": debug: "
<< "Elaborate method (task) scope "
<< scope_path(method_scope) << endl;
}
cur->second->elaborate_scope(des, method_scope);
}
for (map<perm_string,PFunction*>::iterator cur = pclass->funcs.begin()
; cur != pclass->funcs.end() ; ++cur) {
cerr << cur->second->get_fileline() << ": sorry: "
<< "Class methods (functions) not supported." << endl;
hname_t use_name (cur->first);
NetScope*method_scope = new NetScope(class_scope, use_name, NetScope::FUNC);
// Function methods are always automatic...
method_scope->is_auto(true);
method_scope->set_line(cur->second);
if (debug_scopes) {
cerr << cur->second->get_fileline() << ": debug: "
<< "Elaborate method (function) scope "
<< scope_path(method_scope) << endl;
}
cur->second->elaborate_scope(des, method_scope);
}
scope->add_class(use_class);

View File

@ -25,6 +25,7 @@
# include <iostream>
# include "Module.h"
# include "PClass.h"
# include "PExpr.h"
# include "PGate.h"
# include "PGenerate.h"
@ -182,6 +183,15 @@ static void elaborate_sig_tasks(Design*des, NetScope*scope,
}
}
static void elaborate_sig_classes(Design*des, NetScope*scope,
const map<perm_string,PClass*>&classes)
{
for (map<perm_string,PClass*>::const_iterator cur = classes.begin()
; cur != classes.end() ; ++ cur) {
netclass_t*use_class = scope->find_class(cur->second->pscope_name());
use_class->elaborate_sig(des, cur->second);
}
}
bool Module::elaborate_sig(Design*des, NetScope*scope) const
{
@ -262,6 +272,7 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
elaborate_sig_funcs(des, scope, funcs);
elaborate_sig_tasks(des, scope, tasks);
elaborate_sig_classes(des, scope, classes);
// initial and always blocks may contain begin-end and
// fork-join blocks that can introduce scopes. Therefore, I
@ -278,6 +289,34 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
return flag;
}
void netclass_t::elaborate_sig(Design*des, PClass*pclass)
{
for (map<perm_string,PFunction*>::iterator cur = pclass->funcs.begin()
; cur != pclass->funcs.end() ; ++ cur) {
if (debug_elaborate) {
cerr << cur->second->get_fileline() << ": netclass_t::elaborate_sig: "
<< "Elaborate signals in function method " << cur->first << endl;
}
NetScope*scope = class_scope_->child( hname_t(cur->first) );
ivl_assert(*cur->second, scope);
cur->second->elaborate_sig(des, scope);
}
for (map<perm_string,PTask*>::iterator cur = pclass->tasks.begin()
; cur != pclass->tasks.end() ; ++ cur) {
if (debug_elaborate) {
cerr << cur->second->get_fileline() << ": netclass_t::elaborate_sig: "
<< "Elaborate signals in task method " << cur->first << endl;
}
NetScope*scope = class_scope_->child( hname_t(cur->first) );
ivl_assert(*cur->second, scope);
cur->second->elaborate_sig(des, scope);
}
}
bool PGate::elaborate_sig(Design*, NetScope*) const
{
return true;
@ -475,17 +514,6 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
elaborate_sig_wires_(des, scope);
/* Make sure the function has at least one input port. If it
fails this test, print an error message. Keep going so we
can find more errors. */
if (ports_ == 0 && !gn_system_verilog()) {
cerr << get_fileline() << ": error: Function " << fname
<< " has no ports." << endl;
cerr << get_fileline() << ": : Functions must have"
<< " at least one input port." << endl;
des->errors += 1;
}
NetNet*ret_sig = 0;
netvector_t*ret_vec = 0;
@ -621,63 +649,15 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
break;
default:
if (ports_) {
cerr << get_fileline() << ": internal error: I don't know "
<< "how to deal with return type of function "
<< scope->basename() << "." << endl;
} else {
/* If we do not have any ports or a return type this
* is probably a bad function definition. */
cerr << get_fileline() << ": error: Bad definition for "
<< "function " << scope->basename() << "?" << endl;
return;
}
/* If we do not have any ports or a return type this
* is probably a bad function definition. */
cerr << get_fileline() << ": error: Bad definition for "
<< "function " << scope->basename() << "?" << endl;
return;
}
vector<NetNet*>ports (ports_? ports_->size() : 0);
if (ports_)
for (unsigned idx = 0 ; idx < ports_->size() ; idx += 1) {
/* Parse the port name into the task name and the reg
name. We know by design that the port name is given
as two components: <func>.<port>. */
perm_string pname = (*ports_)[idx]->basename();
NetNet*tmp = scope->find_signal(pname);
ports[idx] = 0;
if (tmp == 0) {
cerr << get_fileline() << ": internal error: function "
<< scope_path(scope) << " is missing port "
<< pname << "." << endl;
scope->dump(cerr);
cerr << get_fileline() << ": Continuing..." << endl;
des->errors += 1;
continue;
}
if (tmp->port_type() == NetNet::NOT_A_PORT) {
cerr << get_fileline() << ": internal error: function "
<< scope_path(scope) << " port " << pname
<< " is a port but is not a port?" << endl;
des->errors += 1;
scope->dump(cerr);
continue;
}
ports[idx] = tmp;
if (tmp->port_type() != NetNet::PINPUT) {
cerr << tmp->get_fileline() << ": error: function "
<< scope_path(scope) << " port " << pname
<< " is not an input port." << endl;
cerr << tmp->get_fileline() << ": : Function arguments "
<< "must be input ports." << endl;
des->errors += 1;
}
}
vector<NetNet*>ports;
elaborate_sig_ports_(des, scope, ports);
NetFuncDef*def = 0;
if (ret_sig) def = new NetFuncDef(scope, ret_sig, ports);
@ -710,27 +690,8 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const
elaborate_sig_wires_(des, scope);
svector<NetNet*>ports (ports_? ports_->size() : 0);
for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) {
perm_string port_name = (*ports_)[idx]->basename();
/* Find the signal for the port. We know by definition
that it is in the scope of the task, so look only in
the scope. */
NetNet*tmp = scope->find_signal(port_name);
if (tmp == 0) {
cerr << get_fileline() << ": internal error: "
<< "Could not find port " << port_name
<< " in scope " << scope_path(scope) << endl;
scope->dump(cerr);
des->errors += 1;
}
ports[idx] = tmp;
}
vector<NetNet*>ports;
elaborate_sig_ports_(des, scope, ports);
NetTaskDef*def = new NetTaskDef(scope, ports);
scope->set_task_def(def);
@ -739,6 +700,68 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const
statement_->elaborate_sig(des, scope);
}
void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope,
vector<NetNet*>&ports) const
{
if (ports_ == 0) {
ports.clear();
/* Make sure the function has at least one input
port. If it fails this test, print an error
message. Keep going so we can find more errors. */
if (scope->type()==NetScope::FUNC && !gn_system_verilog()) {
cerr << get_fileline() << ": error: "
<< "Function " << scope->basename()
<< " has no ports." << endl;
cerr << get_fileline() << ": : "
<< "Functions must have at least one input port." << endl;
des->errors += 1;
}
return;
}
ports.resize(ports_->size());
for (size_t idx = 0 ; idx < ports_->size() ; idx += 1) {
perm_string port_name = ports_->at(idx)->basename();
ports[idx] = 0;
NetNet*tmp = scope->find_signal(port_name);
if (tmp == 0) {
cerr << get_fileline() << ": internal error: "
<< "task/function " << scope_path(scope)
<< " is missing port " << port_name << "." << endl;
scope->dump(cerr);
cerr << get_fileline() << ": Continuing..." << endl;
des->errors += 1;
continue;
}
if (tmp->port_type() == NetNet::NOT_A_PORT) {
cerr << get_fileline() << ": internal error: "
<< "task/function " << scope_path(scope)
<< " port " << port_name
<< " is a port but is not a port?" << endl;
des->errors += 1;
scope->dump(cerr);
continue;
}
ports[idx] = tmp;
if (scope->type()==NetScope::FUNC && tmp->port_type()!=NetNet::PINPUT) {
cerr << tmp->get_fileline() << ": error: "
<< "Function " << scope_path(scope)
<< " port " << port_name
<< " is not an inputport." << endl;
cerr << tmp->get_fileline() << ": : "
<< "Function arguments must be input ports." << endl;
des->errors += 1;
}
}
}
void PBlock::elaborate_sig(Design*des, NetScope*scope) const
{
NetScope*my_scope = scope;
@ -1210,6 +1233,18 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
// do right now is locate the netclass_t object for the
// class, and use that to build the net.
netclass_t*use_type = locate_class_type(des, scope, class_type);
if (use_type == 0) {
cerr << get_fileline() << ": internal error: "
<< "Class " << class_type->name
<< " isn't elaborated in scope=" << scope_path(scope) << endl;
des->errors += 1;
}
ivl_assert(*this, use_type);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "Create class instance signal " << wtype
<< " " << name_ << endl;
}
// (No arrays of classes)
list<netrange_t> use_unpacked;
sig = new NetNet(scope, name_, wtype, use_unpacked, use_type);

View File

@ -31,6 +31,7 @@
# include <sstream>
# include <list>
# include "pform.h"
# include "PClass.h"
# include "PEvent.h"
# include "PGenerate.h"
# include "PPackage.h"
@ -3325,6 +3326,20 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const
return sys;
}
if (netclass_t*class_type = net->class_type()) {
NetScope*task = class_type->method_from_name(method_name);
if (task == 0) {
cerr << get_fileline() << ": XXXXX: "
<< "Can't find task " << method_name
<< " in class " << class_type->get_name() << endl;
return 0;
}
NetUTask*tmp = new NetUTask(task);
tmp->set_line(*this);
return tmp;
}
return 0;
}
@ -4679,6 +4694,16 @@ static void elaborate_tasks(Design*des, NetScope*scope,
}
}
static void elaborate_classes(Design*des, NetScope*scope,
const map<perm_string,PClass*>&classes)
{
for (map<perm_string,PClass*>::const_iterator cur = classes.begin()
; cur != classes.end() ; ++ cur) {
netclass_t*use_class = scope->find_class(cur->second->pscope_name());
use_class->elaborate(des, cur->second);
}
}
/*
* When a module is instantiated, it creates the scope then uses this
* method to elaborate the contents of the module.
@ -4703,6 +4728,9 @@ bool Module::elaborate(Design*des, NetScope*scope) const
// the signals so that the tasks can reference them.
elaborate_tasks(des, scope, tasks);
// Elaboate class definitions.
elaborate_classes(des, scope, classes);
// Get all the gates of the module and elaborate them by
// connecting them to the signals. The gate may be simple or
// complex.
@ -4730,6 +4758,42 @@ bool Module::elaborate(Design*des, NetScope*scope) const
return result_flag;
}
/*
* Elaborating a netclass_t means elaborating the PFunction and PTask
* objects that it contains. The scopes and signals have already been
* elaborated in the class of the netclass_t scope, so we can get the
* child scope for each definition and use that for the context of the
* function.
*/
void netclass_t::elaborate(Design*des, PClass*pclass)
{
for (map<perm_string,PFunction*>::iterator cur = pclass->funcs.begin()
; cur != pclass->funcs.end() ; ++ cur) {
if (debug_elaborate) {
cerr << cur->second->get_fileline() << ": netclass_t::elaborate: "
<< "Elaborate class " << scope_path(class_scope_)
<< " function method " << cur->first << endl;
}
NetScope*scope = class_scope_->child( hname_t(cur->first) );
ivl_assert(*cur->second, scope);
cur->second->elaborate(des, scope);
}
for (map<perm_string,PTask*>::iterator cur = pclass->tasks.begin()
; cur != pclass->tasks.end() ; ++ cur) {
if (debug_elaborate) {
cerr << cur->second->get_fileline() << ": netclass_t::elaborate: "
<< "Elaborate class " << scope_path(class_scope_)
<< " task method " << cur->first << endl;
}
NetScope*scope = class_scope_->child( hname_t(cur->first) );
ivl_assert(*cur->second, scope);
cur->second->elaborate(des, scope);
}
}
bool PGenerate::elaborate(Design*des, NetScope*container) const
{
if (direct_nested_)

View File

@ -50,6 +50,7 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, bo
in_final_ = false;
if (up) {
assert(t!=CLASS);
need_const_func_ = up->need_const_func_;
is_const_func_ = up->is_const_func_;
time_unit_ = up->time_unit();
@ -63,7 +64,7 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, bo
time_unit_ = 0;
time_prec_ = 0;
time_from_timescale_ = false;
assert(t==MODULE || t==PACKAGE);
assert(t==MODULE || t==PACKAGE || t==CLASS);
}
switch (t) {
@ -77,6 +78,9 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, bo
case NetScope::PACKAGE:
module_name_ = perm_string();
break;
case NetScope::CLASS:
class_def_ = 0;
break;
default: /* BEGIN_END and FORK_JOIN, do nothing */
break;
}
@ -311,9 +315,12 @@ void NetScope::print_type(ostream&stream) const
case GENBLOCK:
stream << "generate block";
break;
case PACKAGE:
case PACKAGE:
stream << "package " << module_name_;
break;
case CLASS:
stream << "class";
break;
}
}
@ -360,6 +367,21 @@ const NetFuncDef* NetScope::func_def() const
return func_;
}
void NetScope::set_class_def(netclass_t*def)
{
assert( type_ == CLASS );
assert( class_def_==0 );
class_def_ = def;
}
const netclass_t* NetScope::class_def(void) const
{
if (type_==CLASS)
return class_def_;
else
return 0;
}
void NetScope::set_module_name(perm_string n)
{
assert(type_==MODULE || type_==PACKAGE);
@ -563,11 +585,27 @@ void NetScope::add_class(netclass_t*net_class)
netclass_t*NetScope::find_class(perm_string name)
{
// Special class: The scope itself is the class that we are
// looking for. This may happen for example when elaborating
// methods within the class.
if (type_==CLASS && name_==hname_t(name))
return class_def_;
// Look for the class that directly within this scope.
map<perm_string,netclass_t*>::const_iterator cur = classes_.find(name);
if (cur == classes_.end())
return 0;
else
if (cur != classes_.end())
return cur->second;
// If this is a module scope, then look no further.
if (type_==MODULE)
return 0;
// If there is no further to look, ...
if (up_ == 0)
return 0;
// Try looking up for the class.
return up_->find_class(name);
}
/*

View File

@ -18,12 +18,13 @@
*/
# include "netclass.h"
# include "netlist.h"
# include <iostream>
using namespace std;
netclass_t::netclass_t(perm_string name)
: name_(name)
: name_(name), class_scope_(0)
{
}
@ -47,6 +48,12 @@ bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype)
return true;
}
void netclass_t::set_class_scope(NetScope*class_scope)
{
assert(class_scope_ == 0);
class_scope_ = class_scope;
}
ivl_variable_type_t netclass_t::base_type() const
{
return IVL_VT_CLASS;
@ -84,3 +91,11 @@ ivl_type_t netclass_t::get_prop_type(size_t idx) const
assert(idx < property_table_.size());
return property_table_[idx].type;
}
NetScope*netclass_t::method_from_name(perm_string name)
{
NetScope*task = class_scope_->child( hname_t(name) );
if (task == 0) return 0;
return task;
}

View File

@ -22,8 +22,13 @@
# include "LineInfo.h"
# include "ivl_target.h"
# include "nettypes.h"
# include <iostream>
# include <map>
class Design;
class NetScope;
class PClass;
class netclass_t : public ivl_type_s {
public:
netclass_t(perm_string class_name);
@ -34,6 +39,10 @@ class netclass_t : public ivl_type_s {
// present, then return false.
bool set_property(perm_string pname, ivl_type_s*ptype);
// Set the scope for the class. The scope has no parents and
// is used for the elaboration of methods (tasks/functions).
void set_class_scope(NetScope*cscope);
// As an ivl_type_s object, the netclass is always an
// ivl_VT_CLASS object.
ivl_variable_type_t base_type() const;
@ -49,6 +58,14 @@ class netclass_t : public ivl_type_s {
int property_idx_from_name(perm_string pname) const;
// The task method scopes from the method name.
NetScope*method_from_name(perm_string mname);
void elaborate_sig(Design*des, PClass*pclass);
void elaborate(Design*des, PClass*pclass);
void dump_scope(ostream&fd) const;
private:
perm_string name_;
// Map properrty names to property table index.
@ -59,6 +76,9 @@ class netclass_t : public ivl_type_s {
ivl_type_s* type;
};
std::vector<prop_t> property_table_;
// This holds task/function definitions for methods.
NetScope*class_scope_;
};
#endif

View File

@ -2606,7 +2606,7 @@ unsigned NetUReduce::width() const
return width_;
}
NetTaskDef::NetTaskDef(NetScope*n, const svector<NetNet*>&po)
NetTaskDef::NetTaskDef(NetScope*n, const vector<NetNet*>&po)
: scope_(n), proc_(0), ports_(po)
{
}
@ -2624,20 +2624,15 @@ void NetTaskDef::set_proc(NetProc*p)
unsigned NetTaskDef::port_count() const
{
return ports_.count();
return ports_.size();
}
NetNet* NetTaskDef::port(unsigned idx) const
{
assert(idx < ports_.count());
assert(idx < ports_.size());
return ports_[idx];
}
#if 0
const string& NetTaskDef::name() const
{
return name_;
}
#endif
const NetScope* NetTaskDef::scope() const
{
return scope_;

View File

@ -764,7 +764,7 @@ class NetNet : public NetObj, public PortType {
class NetScope : public Attrib {
public:
enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK, PACKAGE };
enum TYPE { MODULE, CLASS, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK, PACKAGE };
/* Create a new scope, and attach it to the given parent. The
name is expected to have been permallocated. */
@ -858,6 +858,7 @@ class NetScope : public Attrib {
void set_task_def(NetTaskDef*);
void set_func_def(NetFuncDef*);
void set_class_def(netclass_t*);
void set_module_name(perm_string);
NetTaskDef* task_def();
@ -919,6 +920,7 @@ class NetScope : public Attrib {
const NetTaskDef* task_def() const;
const NetFuncDef* func_def() const;
const netclass_t* class_def() const;
/* If the scope represents a module instance, the module_name
is the name of the module itself. */
@ -1083,6 +1085,7 @@ class NetScope : public Attrib {
union {
NetTaskDef*task_;
NetFuncDef*func_;
netclass_t*class_def_;
};
const PFunction*func_pform_;
unsigned elab_stage_;
@ -3275,7 +3278,7 @@ class NetSTask : public NetProc {
class NetTaskDef {
public:
NetTaskDef(NetScope*n, const svector<NetNet*>&po);
NetTaskDef(NetScope*n, const vector<NetNet*>&po);
~NetTaskDef();
void set_proc(NetProc*p);
@ -3293,7 +3296,7 @@ class NetTaskDef {
private:
NetScope*scope_;
NetProc*proc_;
svector<NetNet*>ports_;
vector<NetNet*>ports_;
private: // not implemented
NetTaskDef(const NetTaskDef&);

10
parse.y
View File

@ -1032,7 +1032,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */
{ current_function->set_ports($7);
current_function->set_return($3);
current_function_set_statement($8? @8 : @4, $8);
pform_set_this_class(current_function);
pform_set_this_class(@4, current_function);
pform_pop_scope();
current_function = 0;
}
@ -1059,7 +1059,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */
{ current_function->set_ports($7);
current_function->set_return($3);
current_function_set_statement($11? @11 : @4, $11);
pform_set_this_class(current_function);
pform_set_this_class(@4, current_function);
pform_pop_scope();
current_function = 0;
if ($7==0 && !gn_system_verilog()) {
@ -1519,7 +1519,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
K_endtask
{ current_task->set_ports($6);
current_task_set_statement(@3, $7);
pform_set_this_class(current_task);
pform_set_this_class(@3, current_task);
pform_pop_scope();
current_task = 0;
if ($7 && $7->size() > 1 && !gn_system_verilog()) {
@ -1553,7 +1553,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
K_endtask
{ current_task->set_ports($6);
current_task_set_statement(@3, $10);
pform_set_this_class(current_task);
pform_set_this_class(@3, current_task);
pform_pop_scope();
current_task = 0;
if ($10) delete $10;
@ -1583,7 +1583,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
K_endtask
{ current_task->set_ports(0);
current_task_set_statement(@3, $9);
pform_set_this_class(current_task);
pform_set_this_class(@3, current_task);
if (! current_task->method_of()) {
cerr << @3 << ": warning: task definition for \"" << $3
<< "\" has an empty port declaration list!" << endl;

View File

@ -2346,6 +2346,35 @@ vector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
return res;
}
static vector<PWire*>*do_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
ivl_variable_type_t var_type,
data_type_t*data_type,
list<perm_string>*names)
{
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
assert(names);
vector<PWire*>*res = new vector<PWire*>(0);
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++cur) {
perm_string name = *cur;
PWire*curw = pform_get_wire_in_scope(name);
if (curw) {
curw->set_port_type(pt);
} else {
curw = new PWire(name, NetNet::IMPLICIT_REG, pt, var_type);
FILE_NAME(curw, loc);
curw->set_data_type(data_type);
pform_put_wire_in_scope(name, curw);
}
res->push_back(curw);
}
delete names;
return res;
}
vector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
data_type_t*vtype,
@ -2370,8 +2399,11 @@ vector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
true, 0, names);
}
VLerror(loc, "sorry: Given type not supported here.");
return 0;
if (class_type_t*class_type = dynamic_cast<class_type_t*> (vtype)) {
return do_make_task_ports(loc, pt, IVL_VT_CLASS, class_type, names);
}
return do_make_task_ports(loc, pt, IVL_VT_NO_TYPE, vtype, names);
}
/*

View File

@ -185,7 +185,7 @@ extern void pform_class_property(const struct vlltype&loc,
property_qualifier_t pq,
data_type_t*data_type,
std::list<decl_assignment_t*>*decls);
extern void pform_set_this_class(PTaskFunc*net);
extern void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net);
extern void pform_end_class_declaration(void);

View File

@ -911,12 +911,7 @@ void PFunction::dump(ostream&out, unsigned ind) const
if (method_of())
out << setw(ind) << "" << "method of " << method_of()->name << ";" << endl;
if (ports_)
for (unsigned idx = 0 ; idx < ports_->size() ; idx += 1) {
out << setw(ind) << "";
out << "input ";
out << (*ports_)[idx]->basename() << ";" << endl;
}
dump_ports_(out, ind);
dump_parameters_(out, ind);
@ -951,35 +946,7 @@ void PTask::dump(ostream&out, unsigned ind) const
out << pscope_name() << ";" << endl;
if (method_of())
out << setw(ind) << "" << "method of " << method_of()->name << ";" << endl;
if (ports_)
for (unsigned idx = 0 ; idx < ports_->size() ; idx += 1) {
if ((*ports_)[idx] == 0) {
out << setw(ind) << "" << "ERROR PORT" << endl;
continue;
}
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;
case NetNet::PIMPLICIT:
out << "PIMPLICIT";
break;
case NetNet::NOT_A_PORT:
out << "NOT_A_PORT";
break;
default:
assert(0);
break;
}
out << (*ports_)[idx]->basename() << ";" << endl;
}
dump_ports_(out, ind);
dump_parameters_(out, ind);
@ -995,6 +962,42 @@ void PTask::dump(ostream&out, unsigned ind) const
out << setw(ind) << "" << "/* NOOP */" << endl;
}
void PTaskFunc::dump_ports_(std::ostream&out, unsigned ind) const
{
if (ports_ == 0)
return;
for (unsigned idx = 0 ; idx < ports_->size() ; idx += 1) {
if (ports_->at(idx) == 0) {
out << setw(ind) << "" << "ERROR PORT" << endl;
continue;
}
out << setw(ind) << "";
switch (ports_->at(idx)->get_port_type()) {
case NetNet::PINPUT:
out << "input ";
break;
case NetNet::POUTPUT:
out << "output ";
break;
case NetNet::PINOUT:
out << "inout ";
break;
case NetNet::PIMPLICIT:
out << "PIMPLICIT";
break;
case NetNet::NOT_A_PORT:
out << "NOT_A_PORT";
break;
default:
assert(0);
break;
}
out << ports_->at(idx)->basename() << ";" << endl;
}
}
void PTrigger::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "-> " << event_ << ";" << endl;

View File

@ -72,12 +72,23 @@ void pform_class_property(const struct vlltype&loc,
}
}
void pform_set_this_class(PTaskFunc*net)
void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net)
{
if (pform_cur_class == 0)
return;
net->set_this(pform_cur_class->type);
list<perm_string>*this_name = new list<perm_string>;
this_name->push_back(perm_string::literal("@"));
vector<PWire*>*this_port = pform_make_task_ports(loc, NetNet::PINPUT,
pform_cur_class->type,
this_name);
// The pform_make_task_ports() function deletes the this_name
// object.
PWire*this_wire = this_port->at(0);
delete this_port;
net->set_this(pform_cur_class->type, this_wire);
}
void pform_end_class_declaration(void)

View File

@ -28,6 +28,7 @@
# include <cassert>
# include <cstdlib>
# include "ivl_alloc.h"
# include "ivl_assert.h"
/*
* This is a little convenience function for converting a NetExpr
@ -562,7 +563,8 @@ void dll_target::expr_ufunc(const NetEUFunc*net)
FILE_NAME(expr, net);
expr->u_.ufunc_.def = lookup_scope_(net->func());
assert(expr->u_.ufunc_.def->type_ == IVL_SCT_FUNCTION);
ivl_assert(*net, expr->u_.ufunc_.def);
ivl_assert(*net, expr->u_.ufunc_.def->type_ == IVL_SCT_FUNCTION);
unsigned cnt = net->parm_count();
expr->u_.ufunc_.parms = cnt;

View File

@ -2354,6 +2354,9 @@ void dll_target::scope(const NetScope*net)
scop->type_ = IVL_SCT_GENERATE;
scop->tname_ = scop->name_;
break;
case NetScope::CLASS:
assert(0);
break;
}
}
}