diff --git a/PExpr.h b/PExpr.h index 068cca339..13aa0e22f 100644 --- a/PExpr.h +++ b/PExpr.h @@ -516,6 +516,12 @@ class PEIdent : public PExpr { unsigned expr_wid, unsigned flags) const; + unsigned test_width_method_(Design*des, NetScope*scope, width_mode_t&mode); + NetExpr*elaborate_expr_method_(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/elab_expr.cc b/elab_expr.cc index 928cf39c5..7a66620c3 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -106,6 +106,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type, int context_wid = -1; switch (lv_type) { case IVL_VT_DARRAY: + case IVL_VT_QUEUE: // For these types, use a different elab_and_eval that // uses the lv_net_type. We should eventually transition // all the types to this new form. @@ -2782,6 +2783,48 @@ bool PEIdent::calculate_param_range_(Design*, NetScope*, return true; } +unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&mode) +{ + if (!gn_system_verilog()) + return 0; + if (path_.size() < 2) + return 0; + + pform_name_t use_path = path_; + perm_string member_name = peek_tail_name(path_); + use_path.pop_back(); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::test_width_method_: " + << "Try to find method=" << member_name + << " of signal " << use_path << endl; + } + + NetNet*net = 0; + const NetExpr*par = 0; + NetEvent*eve = 0; + const NetExpr*ex1 = 0, *ex2 = 0; + symbol_search(this, des, scope, use_path, net, par, eve, ex1, ex2); + if (net == 0) { + if (debug_elaborate) + cerr << get_fileline() << ": PEIdent::test_width_method_: " + << "Only nets can have methods, so give up here." << endl; + return 0; + } + + if (const netdarray_t*dtype = net->darray_type()) { + if (member_name == "size") { + expr_type_ = IVL_VT_BOOL; + expr_width_ = 32; + min_width_ = 32; + signed_flag_= true; + return 32; + } + } + + return 0; +} + unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) { NetNet* net = 0; @@ -2796,6 +2839,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) ivl_assert(*this, use_scope); } + if (unsigned tmp = test_width_method_(des, scope, mode)) { + return tmp; + } + NetScope*found_in = symbol_search(this, des, use_scope, path_, net, par, eve, ex1, ex2); @@ -3167,6 +3214,55 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, return tmp; } +NetExpr* PEIdent::elaborate_expr_method_(Design*des, NetScope*scope, + unsigned expr_wid, unsigned flags) const +{ + if (!gn_system_verilog()) + return 0; + if (path_.size() < 2) + return 0; + + pform_name_t use_path = path_; + perm_string member_name = peek_tail_name(path_); + use_path.pop_back(); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr_method_: " + << "Try to find method=" << member_name + << " of signal " << use_path << endl; + } + + NetNet*net = 0; + const NetExpr*par = 0; + NetEvent*eve = 0; + const NetExpr*ex1 = 0, *ex2 = 0; + symbol_search(this, des, scope, use_path, net, par, eve, ex1, ex2); + if (net == 0) { + if (debug_elaborate) + cerr << get_fileline() << ": PEIdent::elaborate_expr_method_: " + << "Only nets can have methods, so give up here." << endl; + return 0; + } + + if (const netdarray_t*dtype = net->darray_type()) { + if (member_name == "size") { + NetESFunc*fun = new NetESFunc("$ivl_queue_method$size", + expr_type_, expr_width_, 1); + fun->set_line(*this); + + NetESignal*arg = new NetESignal(net); + arg->set_line(*net); + + fun->parm(0, arg); + return fun; + } + + return 0; + } + + return 0; +} + /* * 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 @@ -3227,6 +3323,14 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, ivl_assert(*this, use_scope); } + // Special case: Detect the special situation that the name is + // a method of an object (including built-in methods) that has + // no arguments. For example, "foo.size" is the call to the + // size() method if foo is an array type. + if (NetExpr*tmp = elaborate_expr_method_(des, scope, expr_wid, flags)) { + return tmp; + } + NetScope*found_in = symbol_search(this, des, use_scope, path_, net, par, eve, ex1, ex2);