From 17330a30737fe800a0c48dfaa0ed7685db2015cf Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 14 Mar 2013 20:08:32 -0700 Subject: [PATCH] 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" --- PExpr.h | 6 ++ PFunction.cc | 8 +- PTask.cc | 29 ++++--- PTask.h | 16 ++-- design_dump.cc | 22 ++++- elab_expr.cc | 99 +++++++++++++++++++++++ elab_lval.cc | 38 +++++++++ elab_scope.cc | 44 +++++++++- elab_sig.cc | 209 ++++++++++++++++++++++++++++-------------------- elaborate.cc | 64 +++++++++++++++ net_scope.cc | 48 +++++++++-- netclass.cc | 17 +++- netclass.h | 20 +++++ netlist.cc | 13 +-- netlist.h | 9 ++- parse.y | 10 +-- pform.cc | 36 ++++++++- pform.h | 2 +- pform_dump.cc | 73 +++++++++-------- pform_pclass.cc | 15 +++- t-dll-expr.cc | 4 +- t-dll.cc | 3 + 22 files changed, 605 insertions(+), 180 deletions(-) diff --git a/PExpr.h b/PExpr.h index 1b434d1a3..58599d1b6 100644 --- a/PExpr.h +++ b/PExpr.h @@ -372,6 +372,7 @@ class PEIdent : public PExpr { std::list&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; diff --git a/PFunction.cc b/PFunction.cc index 47ac34b6a..35eca86c7 100644 --- a/PFunction.cc +++ b/PFunction.cc @@ -22,7 +22,7 @@ # include 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*p) -{ - assert(ports_ == 0); - ports_ = p; -} - void PFunction::set_statement(Statement*s) { assert(s != 0); diff --git a/PTask.cc b/PTask.cc index e3c2e542b..d2ca8e717 100644 --- a/PTask.cc +++ b/PTask.cc @@ -22,7 +22,7 @@ # include 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*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; + + 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*p) -{ - assert(ports_ == 0); - ports_ = p; -} - void PTask::set_statement(Statement*s) { assert(statement_ == 0); diff --git a/PTask.h b/PTask.h index e590f3cad..4fce2369e 100644 --- a/PTask.h +++ b/PTask.h @@ -26,6 +26,7 @@ # include # include 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*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&ports) const; + + void dump_ports_(std::ostream&out, unsigned ind) const; + private: class_type_t*this_type_; + std::vector*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*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*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*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 *ports_; Statement *statement_; bool is_auto_; }; diff --git a/design_dump.cc b/design_dump.cc index b908f3c72..6dc20b581 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -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::const_iterator cur = children_.begin() ; cur != children_.end() ; ++ cur ) cur->second->dump(o); + + for (map::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) { diff --git a/elab_expr.cc b/elab_expr.cc index 9a0345054..157e1982a 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -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); + + vectorparms; + 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" diff --git a/elab_lval.cc b/elab_lval.cc index 9e3e9776c..02095f800 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -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 diff --git a/elab_scope.cc b/elab_scope.cc index a1f584e0c..70e8b4d97 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -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::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::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::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); diff --git a/elab_sig.cc b/elab_sig.cc index 10b5e4875..7d2871a34 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -25,6 +25,7 @@ # include # 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&classes) +{ + for (map::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::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::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; } - vectorports (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: .. */ - - 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; - } - } - + vectorports; + 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); - svectorports (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; - } - + vectorports; + 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&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 use_unpacked; sig = new NetNet(scope, name_, wtype, use_unpacked, use_type); diff --git a/elaborate.cc b/elaborate.cc index 09e0f38aa..57e9ecaa2 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -31,6 +31,7 @@ # include # include # 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&classes) +{ + for (map::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::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::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_) diff --git a/net_scope.cc b/net_scope.cc index 4147f1362..aa02ba390 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -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::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); } /* diff --git a/netclass.cc b/netclass.cc index 6561d824e..f28b78c18 100644 --- a/netclass.cc +++ b/netclass.cc @@ -18,12 +18,13 @@ */ # include "netclass.h" +# include "netlist.h" # include 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; + +} diff --git a/netclass.h b/netclass.h index bfbb0285d..998900a37 100644 --- a/netclass.h +++ b/netclass.h @@ -22,8 +22,13 @@ # include "LineInfo.h" # include "ivl_target.h" # include "nettypes.h" +# include # include +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 property_table_; + + // This holds task/function definitions for methods. + NetScope*class_scope_; }; #endif diff --git a/netlist.cc b/netlist.cc index c241d083a..bcaddb7f1 100644 --- a/netlist.cc +++ b/netlist.cc @@ -2606,7 +2606,7 @@ unsigned NetUReduce::width() const return width_; } -NetTaskDef::NetTaskDef(NetScope*n, const svector&po) +NetTaskDef::NetTaskDef(NetScope*n, const vector&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_; diff --git a/netlist.h b/netlist.h index 2ec36da49..75bee0bfd 100644 --- a/netlist.h +++ b/netlist.h @@ -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&po); + NetTaskDef(NetScope*n, const vector&po); ~NetTaskDef(); void set_proc(NetProc*p); @@ -3293,7 +3296,7 @@ class NetTaskDef { private: NetScope*scope_; NetProc*proc_; - svectorports_; + vectorports_; private: // not implemented NetTaskDef(const NetTaskDef&); diff --git a/parse.y b/parse.y index 3733513bf..ffa9c5faf 100644 --- a/parse.y +++ b/parse.y @@ -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; diff --git a/pform.cc b/pform.cc index 39baa0f27..b7748f9c3 100644 --- a/pform.cc +++ b/pform.cc @@ -2346,6 +2346,35 @@ vector*pform_make_task_ports(const struct vlltype&loc, return res; } +static vector*do_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, + ivl_variable_type_t var_type, + data_type_t*data_type, + list*names) +{ + assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); + assert(names); + vector*res = new vector(0); + + for (list::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*pform_make_task_ports(const struct vlltype&loc, NetNet::PortType pt, data_type_t*vtype, @@ -2370,8 +2399,11 @@ vector*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 (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); } /* diff --git a/pform.h b/pform.h index 4f6174f0a..e1ac7e1a9 100644 --- a/pform.h +++ b/pform.h @@ -185,7 +185,7 @@ extern void pform_class_property(const struct vlltype&loc, property_qualifier_t pq, data_type_t*data_type, std::list*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); diff --git a/pform_dump.cc b/pform_dump.cc index 2978ed816..1b54b275d 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -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; diff --git a/pform_pclass.cc b/pform_pclass.cc index 6b23c57e6..e340d5b8c 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -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*this_name = new list; + this_name->push_back(perm_string::literal("@")); + vector*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) diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 8809dd177..3f7f53709 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -28,6 +28,7 @@ # include # include # 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; diff --git a/t-dll.cc b/t-dll.cc index 8ee4c9805..69cc9a743 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -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; } } }