diff --git a/PExpr.h b/PExpr.h index 29945701a..44c4008a5 100644 --- a/PExpr.h +++ b/PExpr.h @@ -936,7 +936,8 @@ class PECallFunction : public PExpr { NetExpr*elaborate_expr_pkg_(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags)const; NetExpr*elaborate_expr_method_(Design*des, NetScope*scope, - unsigned expr_wid) const; + unsigned expr_wid, + bool add_this_flag = false) const; #if 0 NetExpr*elaborate_expr_string_method_(Design*des, NetScope*scope) const; NetExpr*elaborate_expr_enum_method_(Design*des, NetScope*scope, diff --git a/Statement.h b/Statement.h index a9dcf1297..b650a03f9 100644 --- a/Statement.h +++ b/Statement.h @@ -224,7 +224,8 @@ class PCallTask : public Statement { NetProc* elaborate_sys(Design*des, NetScope*scope) const; NetProc* elaborate_usr(Design*des, NetScope*scope) const; - NetProc*elaborate_method_(Design*des, NetScope*scope) const; + NetProc*elaborate_method_(Design*des, NetScope*scope, + bool add_this_flag = false) const; NetProc*elaborate_function_(Design*des, NetScope*scope) const; NetProc*elaborate_build_call_(Design*des, NetScope*scope, diff --git a/elab_expr.cc b/elab_expr.cc index 965f65075..c64582df4 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -2064,11 +2064,24 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, des->errors += 1; return 0; } - ivl_assert(*this, def); + ivl_assert(*this, def); NetScope*dscope = def->scope(); ivl_assert(*this, dscope); + /* In SystemVerilog a method calling another method in the + * current class needs to be elaborated as a method with an + * implicit this added. */ + if (gn_system_verilog() && (path_.size() == 1)) { + const NetScope *c_scope = scope->get_class_scope(); + if (c_scope && (c_scope == dscope->get_class_scope())) { + NetExpr*tmp = elaborate_expr_method_(des, scope, expr_wid, + true); + assert(tmp); + return tmp; + } + } + bool need_const = NEED_CONST & flags; // It is possible to get here before the called function has been @@ -2262,17 +2275,22 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope, } NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, - unsigned expr_wid) const + unsigned expr_wid, + bool add_this_flag) const { pform_name_t use_path = path_; perm_string method_name = peek_tail_name(use_path); use_path.pop_back(); + /* Add the implicit this reference when requested. */ + if (add_this_flag) { + assert(use_path.empty()); + use_path.push_front(name_component_t(perm_string::literal("@"))); + } + // If there is no object to the left of the method name, then // give up on the idea of looking for an object method. - if (use_path.empty()) { - return 0; - } + if (use_path.empty()) return 0; NetNet *net = 0; const NetExpr *par; diff --git a/elaborate.cc b/elaborate.cc index 3de901cec..409ebe759 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3439,6 +3439,17 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const } assert(def); + /* In SystemVerilog a method calling another method in the + * current class needs to be elaborated as a method with an + * implicit this added. */ + if (gn_system_verilog() && (path_.size() == 1)) { + const NetScope *c_scope = scope->get_class_scope(); + if (c_scope && (c_scope == task->get_class_scope())) { + NetProc *tmp = elaborate_method_(des, scope, true); + assert(tmp); + return tmp; + } + } unsigned parm_count = def->port_count(); @@ -3490,7 +3501,8 @@ NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope, return sys; } -NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const +NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, + bool add_this_flag) const { pform_name_t use_path = path_; perm_string method_name = peek_tail_name(use_path); @@ -3501,6 +3513,12 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const NetEvent *eve; const NetExpr *ex1, *ex2; + /* Add the implicit this reference when requested. */ + if (add_this_flag) { + assert(use_path.empty()); + use_path.push_front(name_component_t(perm_string::literal("@"))); + } + // There is no signal to search for so this cannot be a method. if (use_path.empty()) return 0; diff --git a/net_scope.cc b/net_scope.cc index ead04797b..f3044e9f4 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -691,6 +691,32 @@ const NetScope* NetScope::child(const hname_t&name) const return cur->second; } +/* Helper function to see if the given scope is defined in a class and if + * so return the class scope. */ +const NetScope* NetScope::get_class_scope() const +{ + const NetScope*scope = this; + while (scope) { + switch(scope->type()) { + case NetScope::CLASS: + return scope; + case NetScope::TASK: + case NetScope::FUNC: + case NetScope::BEGIN_END: + case NetScope::FORK_JOIN: + break; + case NetScope::MODULE: + case NetScope::GENBLOCK: + case NetScope::PACKAGE: + return 0; + default: + assert(0); + } + scope = scope->parent(); + } + return scope; +} + const NetScope* NetScope::child_byname(perm_string name) const { hname_t hname (name); diff --git a/netlist.h b/netlist.h index 6d5563fb3..96e8ccc27 100644 --- a/netlist.h +++ b/netlist.h @@ -995,6 +995,9 @@ class NetScope : public Definitions, public Attrib { const NetScope* parent() const { return up_; } const NetScope* child(const hname_t&name) const; + /* A helper function to find the enclosing class scope. */ + const NetScope* get_class_scope() const; + // Look for a child scope by name. This ignores the number // part of the child scope name, so there may be multiple // matches. Only return one. This function is only really