diff --git a/elab_expr.cc b/elab_expr.cc index 83ee2a7eb..66a0d51da 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -47,6 +47,7 @@ using namespace std; static netqueue_t ivl_queue_unique_index_ret(&netvector_t::atom2s32, -1); +static netqueue_t ivl_queue_string_ret(&netstring_t::type_string, -1); static bool queue_method_element_is_integral_vec4(ivl_type_t et) { @@ -54,6 +55,106 @@ static bool queue_method_element_is_integral_vec4(ivl_type_t et) return bt == IVL_VT_BOOL || bt == IVL_VT_LOGIC; } +/* Locator methods: integral vec4 always; string only for find*. */ +static bool locator_method_element_supported(ivl_type_t et, perm_string method) +{ + if (queue_method_element_is_integral_vec4(et)) + return true; + if (ivl_type_base(et) != IVL_VT_STRING) + return false; + return method == "find" || method == "find_index" || + method == "find_first" || method == "find_first_index" || + method == "find_last" || method == "find_last_index"; +} + +/* + * No-parens forms (e.g. qi = s.unique) elaborate as PEIdent. Build the + * same NetESFunc used for s.unique() / queue methods. + */ +static NetExpr* elab_array_locator_noparens(Design* des, const LineInfo& loc, + NetNet* net, perm_string method_name, + const char* kind) +{ + const netdarray_t* dar = net->darray_type(); + ivl_assert(loc, dar); + ivl_type_t element_type = dar->element_type(); + const netqueue_t* queue = net->queue_type(); + ivl_type_t value_rtype = queue + ? static_cast(queue) + : (ivl_type_base(element_type) == IVL_VT_STRING + ? static_cast(&ivl_queue_string_ret) + : static_cast(dar)); + + if (method_name == "size") { + NetESFunc*fun = new NetESFunc("$size", &netvector_t::atom2s32, 1); + fun->set_line(loc); + NetESignal*arg = new NetESignal(net); + arg->set_line(*net); + fun->parm(0, arg); + return fun; + } + + if (method_name == "unique" || method_name == "unique_index" || + method_name == "min" || method_name == "max" || + method_name == "sum" || method_name == "product" || + method_name == "and" || method_name == "or" || + method_name == "xor") { + if (method_name == "sum" || method_name == "product" || + method_name == "and" || method_name == "or" || + method_name == "xor") { + if (!queue_method_element_is_integral_vec4(element_type)) { + cerr << loc.get_fileline() << ": sorry: " << kind << " " + << method_name << "() for this " + << "element type is not yet supported." << endl; + des->errors += 1; + return 0; + } + } else if (!queue_method_element_is_integral_vec4(element_type)) { + cerr << loc.get_fileline() << ": sorry: " << kind << " " + << method_name << "() for this " + << "element type is not yet supported." << endl; + des->errors += 1; + return 0; + } + + ivl_type_t result_type; + char sfunc[64]; + if (method_name == "unique_index") { + result_type = &ivl_queue_unique_index_ret; + snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$unique_index"); + } else if (method_name == "sum" || method_name == "product" || + method_name == "and" || method_name == "or" || + method_name == "xor") { + result_type = element_type; + snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s", + method_name.str()); + } else { + result_type = value_rtype; + snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s", + method_name.str()); + } + NetESFunc*fun = new NetESFunc(sfunc, result_type, 1); + fun->set_line(loc); + NetESignal*arg = new NetESignal(net); + arg->set_line(*net); + fun->parm(0, arg); + return fun; + } + + if (method_name == "find" || method_name == "find_index" || + method_name == "find_first" || method_name == "find_first_index" || + method_name == "find_last" || method_name == "find_last_index") { + cerr << loc.get_fileline() << ": error: Array locator method `" + << method_name << "' must be called with one " + << "argument, e.g. " << method_name << "(value)." + << endl; + des->errors += 1; + return 0; + } + + return 0; +} + /* One argument: value to match using == (same as find with (item == arg)). */ static NetExpr* elab_queue_locator_cmp_arg(Design* des, NetScope* scope, const LineInfo& loc, @@ -91,12 +192,19 @@ static NetExpr* elab_queue_locator_with_predicate( NetScope::BEGIN_END); ws->set_line(&loc); - unsigned ew = ivl_type_packed_width(element_type); - const netvector_t* item_vec = new netvector_t(ivl_type_base(element_type), - (long)ew - 1, 0, - ivl_type_signed(element_type)); - NetNet* item_net = new NetNet(ws, lex_strings.make("item"), NetNet::REG, - item_vec); + NetNet* item_net; + unsigned ew = 0; + if (ivl_type_base(element_type) == IVL_VT_STRING) { + item_net = new NetNet(ws, lex_strings.make("item"), NetNet::REG, + &netstring_t::type_string); + } else { + ew = ivl_type_packed_width(element_type); + const netvector_t* item_vec = new netvector_t(ivl_type_base(element_type), + (long)ew - 1, 0, + ivl_type_signed(element_type)); + item_net = new NetNet(ws, lex_strings.make("item"), NetNet::REG, + item_vec); + } item_net->set_line(loc); item_net->local_flag(true); @@ -106,7 +214,9 @@ static NetExpr* elab_queue_locator_with_predicate( index_net->local_flag(true); NetExpr* pred = 0; - if (method_suffix == "sum" || method_suffix == "product") { + if (method_suffix == "sum" || method_suffix == "product" || + method_suffix == "and" || method_suffix == "or" || + method_suffix == "xor") { pred = elab_and_eval(des, ws, with_expr, (int)ew, false, false, ivl_type_base(element_type)); } else { @@ -140,6 +250,12 @@ static NetExpr* elab_queue_locator_with_predicate( sfunc_name = lex_strings.make("$ivl_queue_method$sum_with"); } else if (method_suffix == "product") { sfunc_name = lex_strings.make("$ivl_queue_method$product_with"); + } else if (method_suffix == "and") { + sfunc_name = lex_strings.make("$ivl_queue_method$and_with"); + } else if (method_suffix == "or") { + sfunc_name = lex_strings.make("$ivl_queue_method$or_with"); + } else if (method_suffix == "xor") { + sfunc_name = lex_strings.make("$ivl_queue_method$xor_with"); } else { ivl_assert(loc, 0); } @@ -182,7 +298,7 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope, const vector& parms, PExpr* with_expr, const char* kind) { - if (!queue_method_element_is_integral_vec4(element_type)) { + if (!locator_method_element_supported(element_type, method_name)) { cerr << loc.get_fileline() << ": sorry: " << kind << " " << method_name << "() for this " << "element type is not yet supported." << endl; @@ -190,9 +306,16 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope, return 0; } + ivl_type_t use_value_type = value_queue_type; + if (!locator_returns_indices(method_name) && + ivl_type_base(element_type) == IVL_VT_STRING && + ivl_type_base(value_queue_type) == IVL_VT_DARRAY) { + use_value_type = &ivl_queue_string_ret; + } + ivl_type_t result_type = locator_returns_indices(method_name) ? static_cast(&ivl_queue_unique_index_ret) - : value_queue_type; + : use_value_type; char sfunc[64]; snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s", method_name.str()); @@ -237,11 +360,41 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope, static bool is_array_reduction_method(perm_string name) { - return name == "sum" || name == "product"; + return name == "sum" || name == "product" || + name == "and" || name == "or" || name == "xor"; } /* - * Elaborate sum()/product() on a queue or dynamic array expression. + * LRM 7.12.4: iterator index querying. In `with` predicates the iterator + * exposes `.index`. Icarus models that as a sibling local net named `index` + * in the synthetic `$ivl_qwith*` scope; map `item.index` to that net. + */ +static NetExpr* elab_array_iterator_index_query(const LineInfo& loc, + const symbol_search_results& sr) +{ + if (!sr.net || sr.path_tail.size() != 1) + return 0; + if (sr.path_tail.front().name != "index" || + !sr.path_tail.front().index.empty()) + return 0; + if (sr.net->name() != "item") + return 0; + NetScope* sc = sr.net->scope(); + if (!sc) + return 0; + perm_string sn = sc->basename(); + if (!sn.str() || strncmp(sn.str(), "$ivl_qwith", 10) != 0) + return 0; + NetNet* idx = sc->find_signal(lex_strings.make("index")); + if (!idx) + return 0; + NetESignal* tmp = new NetESignal(idx); + tmp->set_line(loc); + return tmp; +} + +/* + * Elaborate sum()/product()/and()/or()/xor() on a queue or dynamic array. * Returns an integral value with the element type/width. */ static NetExpr* elab_array_reduction_method(Design* des, NetScope* scope, @@ -1900,7 +2053,9 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*, return expr_width_; } - if (method_name == "sum" || method_name == "product") { + if (method_name == "sum" || method_name == "product" || + method_name == "and" || method_name == "or" || + method_name == "xor") { expr_type_ = darray->element_base_type(); expr_width_ = darray->element_width(); min_width_ = expr_width_; @@ -5145,6 +5300,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, NetNet *net = sr.net; + if (NetExpr* idxq = elab_array_iterator_index_query(*this, sr)) + return idxq; + if (!sr.path_tail.empty()) { if (net->struct_type()) { return check_for_struct_members(this, des, scope, net, @@ -5261,6 +5419,24 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, fun->parm(0, arg); return fun; } + if (member_comp.name == "and" || member_comp.name == "or" || + member_comp.name == "xor") { + if (!queue_method_element_is_integral_vec4(element_type)) { + cerr << get_fileline() << ": sorry: queue " << member_comp.name + << "() for this element type is not yet supported." << endl; + des->errors += 1; + return 0; + } + char sfunc[64]; + snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s", + member_comp.name.str()); + NetESFunc*fun = new NetESFunc(sfunc, element_type, 1); + fun->set_line(*this); + NetESignal*arg = new NetESignal(sr.net); + arg->set_line(*sr.net); + fun->parm(0, arg); + return fun; + } if (member_comp.name == "min" || member_comp.name == "max") { if (!queue_method_element_is_integral_vec4(element_type)) { cerr << get_fileline() << ": sorry: queue " << member_comp.name @@ -5284,6 +5460,21 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, return 0; } + // Dynamic array methods without parentheses (e.g. qi = s.unique). + // Must run before the typed assign fallthrough that treats path_tail + // as a field and compares the array to the context queue type. + if (sr.net->darray_type() && !sr.net->queue_type() && + (path_.size() > 1 || !sr.path_tail.empty())) { + const name_component_t member_comp = !sr.path_tail.empty() + ? sr.path_tail.front() + : path_.back(); + NetExpr*tmp = elab_array_locator_noparens(des, *this, sr.net, + member_comp.name, + "dynamic array"); + if (tmp) return tmp; + if (des->errors) return 0; + } + ivl_type_t check_type = ntype; if (const netdarray_t*array_type = dynamic_cast (ntype)) { if (array_type->type_compatible(net->net_type()) && @@ -5473,6 +5664,9 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, if (!check_interface_modport_access(this, des, sr, false)) return 0; + if (NetExpr* idxq = elab_array_iterator_index_query(*this, sr)) + return idxq; + if (NEED_CONST & flags) { cerr << get_fileline() << ": error: A reference to a net " "or variable (`" << path_ << "') is not allowed in " @@ -5611,6 +5805,27 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, fun->parm(0, arg); return fun; } + if (member_comp.name == "product" || + member_comp.name == "and" || member_comp.name == "or" || + member_comp.name == "xor") { + if (!queue_method_element_is_integral_vec4(element_type)) { + cerr << get_fileline() << ": sorry: queue " + << member_comp.name + << "() for this element type is not yet supported." + << endl; + des->errors += 1; + return 0; + } + char sfunc[64]; + snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s", + member_comp.name.str()); + NetESFunc*fun = new NetESFunc(sfunc, element_type, 1); + fun->set_line(*this); + NetESignal*arg = new NetESignal(sr.net); + arg->set_line(*sr.net); + fun->parm(0, arg); + return fun; + } if (member_comp.name == "min" || member_comp.name == "max") { if (!queue_method_element_is_integral_vec4(element_type)) { cerr << get_fileline() << ": sorry: queue " << member_comp.name @@ -5632,118 +5847,24 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, // Dynamic array (not queue) — array location / reduction methods. if (sr.net->darray_type() && !sr.net->queue_type() && - !sr.path_tail.empty()) { + (path_.size() > 1 || !sr.path_tail.empty())) { if (debug_elaborate) { cerr << get_fileline() << ": PEIdent::elaborate_expr: " "Ident " << sr.path_head - << " looking for array property " << sr.path_tail + << " looking for array property " + << (sr.path_tail.empty() ? path_.back().name + : sr.path_tail.front().name) << endl; } - ivl_assert(*this, sr.path_tail.size() == 1); - const name_component_t member_comp = sr.path_tail.front(); - if (member_comp.name == "size") { - NetESFunc*fun = new NetESFunc("$size", - &netvector_t::atom2s32, - 1); - fun->set_line(*this); - - NetESignal*arg = new NetESignal(sr.net); - arg->set_line(*sr.net); - - fun->parm(0, arg); - return fun; - } else if (member_comp.name == "find" || - member_comp.name == "find_index" || - member_comp.name == "find_first" || - member_comp.name == "find_first_index" || - member_comp.name == "find_last" || - member_comp.name == "find_last_index") { - cerr << get_fileline() << ": error: Array locator method `" - << member_comp.name << "' must be called with one " - << "argument, e.g. " << member_comp.name << "(value)." - << endl; - des->errors += 1; - return 0; - } else if (member_comp.name == "min") { - cerr << get_fileline() << ": sorry: 'min()' " - "array location method is not currently " - "implemented." << endl; - des->errors += 1; - return 0; - } else if (member_comp.name == "max") { - cerr << get_fileline() << ": sorry: 'max()' " - "array location method is not currently " - "implemented." << endl; - des->errors += 1; - return 0; - } else if (member_comp.name == "unique") { - cerr << get_fileline() << ": sorry: 'unique()' " - "array location method is not currently " - "implemented." << endl; - des->errors += 1; - return 0; - } else if (member_comp.name == "unique_index") { - cerr << get_fileline() << ": sorry: 'unique_index()' " - "array location method is not currently " - "implemented." << endl; - des->errors += 1; - return 0; -// FIXME: Check this is a real or integral type. - } else if (member_comp.name == "sum") { - const netdarray_t* dar_sum = sr.net->darray_type(); - ivl_assert(*this, dar_sum); - ivl_type_t element_type = dar_sum->element_type(); - if (!queue_method_element_is_integral_vec4(element_type)) { - cerr << get_fileline() << ": sorry: dynamic array sum() for this " - << "element type is not yet supported." << endl; - des->errors += 1; - return 0; - } - NetESFunc*fun = new NetESFunc("$ivl_queue_method$sum", - element_type, 1); - fun->set_line(*this); - NetESignal*arg = new NetESignal(sr.net); - arg->set_line(*sr.net); - fun->parm(0, arg); - return fun; - } else if (member_comp.name == "product") { - const netdarray_t* dar_sum = sr.net->darray_type(); - ivl_assert(*this, dar_sum); - ivl_type_t element_type = dar_sum->element_type(); - if (!queue_method_element_is_integral_vec4(element_type)) { - cerr << get_fileline() << ": sorry: dynamic array product() for this " - << "element type is not yet supported." << endl; - des->errors += 1; - return 0; - } - NetESFunc*fun = new NetESFunc("$ivl_queue_method$product", - element_type, 1); - fun->set_line(*this); - NetESignal*arg = new NetESignal(sr.net); - arg->set_line(*sr.net); - fun->parm(0, arg); - return fun; -// FIXME: Check this is only an integral type. - } else if (member_comp.name == "and") { - cerr << get_fileline() << ": sorry: 'and()' " - "array reduction method is not currently " - "implemented." << endl; - des->errors += 1; - return 0; - } else if (member_comp.name == "or") { - cerr << get_fileline() << ": sorry: 'or()' " - "array reduction method is not currently " - "implemented." << endl; - des->errors += 1; - return 0; - } else if (member_comp.name == "xor") { - cerr << get_fileline() << ": sorry: 'xor()' " - "array reduction method is not currently " - "implemented." << endl; - des->errors += 1; - return 0; - } + const name_component_t member_comp = !sr.path_tail.empty() + ? sr.path_tail.front() + : path_.back(); + NetExpr*tmp = elab_array_locator_noparens(des, *this, sr.net, + member_comp.name, + "dynamic array"); + if (tmp) return tmp; + if (des->errors) return 0; } if ((sr.net->data_type() == IVL_VT_STRING) && !sr.path_tail.empty()) { diff --git a/ivtest/ivltests/sv_darray_and_or_xor.v b/ivtest/ivltests/sv_darray_and_or_xor.v new file mode 100644 index 000000000..8f9b58b12 --- /dev/null +++ b/ivtest/ivltests/sv_darray_and_or_xor.v @@ -0,0 +1,38 @@ +// Regression: dynamic array and()/or()/xor() reductions (LRM 7.12.3). + +module top; + + bit failed = 0; + + `define CHK(cond) \ + if (!(cond)) begin \ + $display("FAILED line %0d", `__LINE__); \ + failed = 1; \ + end + + byte b[]; + int y; + + initial begin + b = '{1, 3, 5, 7}; + y = b.and; + `CHK(y === 1); + + b = '{1, 2, 3, 4}; + y = b.or; + `CHK(y === 7); + y = b.xor; + `CHK(y === 4); + + b = new[0]; + y = b.and; + `CHK(y === -1); + y = b.or; + `CHK(y === 0); + y = b.xor; + `CHK(y === 0); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_darray_find_locators.v b/ivtest/ivltests/sv_darray_find_locators.v index 009a7d994..21336c85f 100644 --- a/ivtest/ivltests/sv_darray_find_locators.v +++ b/ivtest/ivltests/sv_darray_find_locators.v @@ -12,6 +12,9 @@ module top; int array[] = '{4, 7, 2, 5, 7, 1, 6, 3, 1}; int res[$]; + string s[] = '{"hello", "sad", "hello", "world"}; + string qs[$]; + int qi[$]; initial begin res = array.find() with (item > 3); @@ -42,6 +45,30 @@ module top; `CHK(res.size == 1); `CHK(res[0] == 8); + qs = s.find with (item == "sad"); + `CHK(qs.size == 1); + `CHK(qs[0] == "sad"); + + qs = s.find_first with (item == "hello"); + `CHK(qs.size == 1); + `CHK(qs[0] == "hello"); + + qs = s.find_last with (item == "hello"); + `CHK(qs.size == 1); + `CHK(qs[0] == "hello"); + + qi = s.find_index with (item == "world"); + `CHK(qi.size == 1); + `CHK(qi[0] == 3); + + qi = s.find_first_index with (item == "hello"); + `CHK(qi.size == 1); + `CHK(qi[0] == 0); + + qi = s.find_last_index with (item == "hello"); + `CHK(qi.size == 1); + `CHK(qi[0] == 2); + if (!failed) $display("PASSED"); end diff --git a/ivtest/ivltests/sv_darray_item_index.v b/ivtest/ivltests/sv_darray_item_index.v new file mode 100644 index 000000000..4c0e4fd5a --- /dev/null +++ b/ivtest/ivltests/sv_darray_item_index.v @@ -0,0 +1,26 @@ +// Regression: iterator index querying item.index in with() (LRM 7.12.4). + +module top; + + bit failed = 0; + + `define CHK(cond) \ + if (!(cond)) begin \ + $display("FAILED line %0d", `__LINE__); \ + failed = 1; \ + end + + int arr[] = '{0, 1, 3, 3}; + int q[$]; + + initial begin + q = arr.find with (item == item.index); + `CHK(q.size == 3); + `CHK(q[0] == 0); + `CHK(q[1] == 1); + `CHK(q[2] == 3); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_darray_min_max.v b/ivtest/ivltests/sv_darray_min_max.v index 58265c560..5293961ed 100644 --- a/ivtest/ivltests/sv_darray_min_max.v +++ b/ivtest/ivltests/sv_darray_min_max.v @@ -25,6 +25,13 @@ module top; `CHK(r[0] == 7); `CHK(r[1] == 7); + r = a.min; + `CHK(r.size == 2); + `CHK(r[0] == 1); + r = a.max; + `CHK(r.size == 2); + `CHK(r[0] == 7); + r = empty.min(); `CHK(r.size == 0); r = empty.max(); diff --git a/ivtest/ivltests/sv_darray_unique.v b/ivtest/ivltests/sv_darray_unique.v index ee0b00ef7..8952ee15d 100644 --- a/ivtest/ivltests/sv_darray_unique.v +++ b/ivtest/ivltests/sv_darray_unique.v @@ -23,6 +23,21 @@ module top; `CHK(ix[1] == 1); `CHK(ix[2] == 3); + // No-parentheses forms (sv-tests style), including assign to queue then sort. + u = a.unique; + u.sort; + `CHK(u.size == 3); + `CHK(u[0] == 1); + `CHK(u[1] == 2); + `CHK(u[2] == 3); + + ix = a.unique_index; + ix.sort; + `CHK(ix.size == 3); + `CHK(ix[0] == 0); + `CHK(ix[1] == 1); + `CHK(ix[2] == 3); + if (!failed) $display("PASSED"); end diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 46f62b1aa..cb7462113 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -314,7 +314,9 @@ sv_const_fail7 vvp_tests/sv_const_fail7.json sv_const_fail8 vvp_tests/sv_const_fail8.json sv_const_fail9 vvp_tests/sv_const_fail9.json sv_darray_assign_op vvp_tests/sv_darray_assign_op.json +sv_darray_and_or_xor vvp_tests/sv_darray_and_or_xor.json sv_darray_find_locators vvp_tests/sv_darray_find_locators.json +sv_darray_item_index vvp_tests/sv_darray_item_index.json sv_darray_min_max vvp_tests/sv_darray_min_max.json sv_darray_min_max_with vvp_tests/sv_darray_min_max_with.json sv_darray_product vvp_tests/sv_darray_product.json diff --git a/ivtest/vvp_tests/sv_darray_and_or_xor.json b/ivtest/vvp_tests/sv_darray_and_or_xor.json new file mode 100644 index 000000000..d1b469f2d --- /dev/null +++ b/ivtest/vvp_tests/sv_darray_and_or_xor.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_darray_and_or_xor.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog dynamic array and/or/xor reductions", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_darray_item_index.json b/ivtest/vvp_tests/sv_darray_item_index.json new file mode 100644 index 000000000..ef326a983 --- /dev/null +++ b/ivtest/vvp_tests/sv_darray_item_index.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_darray_item_index.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog array iterator item.index querying", + "type" : "CE" + } +} diff --git a/tgt-vvp/eval_object.c b/tgt-vvp/eval_object.c index abf21480b..7de302e35 100644 --- a/tgt-vvp/eval_object.c +++ b/tgt-vvp/eval_object.c @@ -359,6 +359,25 @@ static unsigned queue_unique_src_elem_wid(ivl_expr_t arg) return 0; } +static int queue_src_elem_is_string(ivl_expr_t arg) +{ + ivl_type_t src_q = 0; + if (ivl_expr_type(arg) == IVL_EX_PROPERTY) { + ivl_signal_t cl = ivl_expr_signal(arg); + unsigned pidx = ivl_expr_property_idx(arg); + src_q = ivl_type_prop_type(ivl_signal_net_type(cl), pidx); + } else if (ivl_expr_type(arg) == IVL_EX_SIGNAL) { + src_q = ivl_signal_net_type(ivl_expr_signal(arg)); + } else { + return 0; + } + if (ivl_type_base(src_q) == IVL_VT_QUEUE || + ivl_type_base(src_q) == IVL_VT_DARRAY) { + return ivl_type_base(ivl_type_element(src_q)) == IVL_VT_STRING; + } + return 0; +} + /* * Emit a queue locator opcode. Plain signal uses `op_v`; class property * uses `op_prop_v`. Returning a queue object leaves it on the object stack. @@ -431,7 +450,10 @@ enum queue_locator_with_mode_e { QUEUE_WITH_UNIQUE, QUEUE_WITH_UNIQUE_INDEX, QUEUE_WITH_SUM, - QUEUE_WITH_PRODUCT + QUEUE_WITH_PRODUCT, + QUEUE_WITH_AND, + QUEUE_WITH_OR, + QUEUE_WITH_XOR }; static enum queue_locator_with_mode_e queue_locator_with_mode_from_name( @@ -461,6 +483,12 @@ static enum queue_locator_with_mode_e queue_locator_with_mode_from_name( return QUEUE_WITH_SUM; } else if (strcmp(name, "$ivl_queue_method$product_with") == 0) { return QUEUE_WITH_PRODUCT; + } else if (strcmp(name, "$ivl_queue_method$and_with") == 0) { + return QUEUE_WITH_AND; + } else if (strcmp(name, "$ivl_queue_method$or_with") == 0) { + return QUEUE_WITH_OR; + } else if (strcmp(name, "$ivl_queue_method$xor_with") == 0) { + return QUEUE_WITH_XOR; } return (enum queue_locator_with_mode_e) -1; } @@ -480,12 +508,19 @@ static int queue_with_multi(enum queue_locator_with_mode_e mode) mode == QUEUE_WITH_UNIQUE || mode == QUEUE_WITH_UNIQUE_INDEX || mode == QUEUE_WITH_SUM || - mode == QUEUE_WITH_PRODUCT; + mode == QUEUE_WITH_PRODUCT || + mode == QUEUE_WITH_AND || + mode == QUEUE_WITH_OR || + mode == QUEUE_WITH_XOR; } static int queue_with_expr_value(enum queue_locator_with_mode_e mode) { - return mode == QUEUE_WITH_SUM || mode == QUEUE_WITH_PRODUCT; + return mode == QUEUE_WITH_SUM || + mode == QUEUE_WITH_PRODUCT || + mode == QUEUE_WITH_AND || + mode == QUEUE_WITH_OR || + mode == QUEUE_WITH_XOR; } static int queue_with_as_index(enum queue_locator_with_mode_e mode) @@ -499,17 +534,24 @@ static int queue_with_as_index(enum queue_locator_with_mode_e mode) /* On predicate match: append value/index and continue or stop. */ static void emit_queue_with_on_match(enum queue_locator_with_mode_e mode, ivl_signal_t item_sig, int i_reg, - unsigned elem_wid, unsigned match_lab) + unsigned elem_wid, unsigned match_lab, + int is_string) { int multi = queue_with_multi(mode); int as_index = queue_with_as_index(mode); if (!multi) { - fprintf(vvp_out, " %%queue/new_empty/v;\n"); + if (is_string && !as_index) + fprintf(vvp_out, " %%queue/new_empty/str;\n"); + else + fprintf(vvp_out, " %%queue/new_empty/v;\n"); } if (as_index) { fprintf(vvp_out, " %%push/ix/vec4 %d, 32, 1;\n", i_reg); fprintf(vvp_out, " %%queue/append_word/v 32;\n"); + } else if (is_string) { + fprintf(vvp_out, " %%load/str v%p_0;\n", item_sig); + fprintf(vvp_out, " %%queue/append_word/str;\n"); } else { fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig); fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid); @@ -554,7 +596,8 @@ static void emit_queue_with_step_index(int reverse, int i_reg, unsigned lab_top) } static void emit_queue_with_finish(enum queue_locator_with_mode_e mode, - int is_prop, unsigned elem_wid) + int is_prop, unsigned elem_wid, + int is_string) { if (mode == QUEUE_WITH_UNIQUE || mode == QUEUE_WITH_UNIQUE_INDEX) { unsigned wid = (mode == QUEUE_WITH_UNIQUE_INDEX) ? 32 : elem_wid; @@ -586,13 +629,37 @@ static void emit_queue_with_finish(enum queue_locator_with_mode_e mode, } return; } + if (mode == QUEUE_WITH_AND) { + fprintf(vvp_out, " %%queue/and/obj/v %u;\n", elem_wid); + if (is_prop) { + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + } + return; + } + if (mode == QUEUE_WITH_OR) { + fprintf(vvp_out, " %%queue/or/obj/v %u;\n", elem_wid); + if (is_prop) { + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + } + return; + } + if (mode == QUEUE_WITH_XOR) { + fprintf(vvp_out, " %%queue/xor/obj/v %u;\n", elem_wid); + if (is_prop) { + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + } + return; + } if (queue_with_multi(mode)) { if (is_prop) { fprintf(vvp_out, " %%pop/obj 1, 1;\n"); } return; } - fprintf(vvp_out, " %%queue/new_empty/v;\n"); + if (is_string && !queue_with_as_index(mode)) + fprintf(vvp_out, " %%queue/new_empty/str;\n"); + else + fprintf(vvp_out, " %%queue/new_empty/v;\n"); if (is_prop) { fprintf(vvp_out, " %%pop/obj 1, 1;\n"); } @@ -610,13 +677,28 @@ static int eval_queue_method_find_with(ivl_expr_t expr) ivl_expr_t pred = ivl_expr_parm(expr, 1); ivl_signal_t item_sig = ivl_expr_signal(ivl_expr_parm(expr, 2)); ivl_signal_t idx_sig = ivl_expr_signal(ivl_expr_parm(expr, 3)); - unsigned elem_wid = queue_unique_src_elem_wid(qarg); - if (elem_wid == 0) return 1; + int is_string = queue_src_elem_is_string(qarg); + unsigned elem_wid = is_string ? 0 : queue_unique_src_elem_wid(qarg); + if (!is_string && elem_wid == 0) return 1; enum queue_locator_with_mode_e mode = queue_locator_with_mode_from_name(name); if ((int) mode < 0) return 1; + /* String unique/min/max/sum/product/and/or/xor with() not implemented yet. */ + if (is_string && + (mode == QUEUE_WITH_UNIQUE || mode == QUEUE_WITH_UNIQUE_INDEX || + mode == QUEUE_WITH_MIN || mode == QUEUE_WITH_MAX || + mode == QUEUE_WITH_SUM || mode == QUEUE_WITH_PRODUCT || + mode == QUEUE_WITH_AND || mode == QUEUE_WITH_OR || + mode == QUEUE_WITH_XOR)) { + return 1; + } + + /* Class-property string locators need %load/prop/dar/str (not yet). */ + if (is_string && (ivl_expr_type(qarg) == IVL_EX_PROPERTY)) + return 1; + int i_reg = allocate_word(); int n_reg = allocate_word(); unsigned lab_top = local_count++; @@ -630,6 +712,10 @@ static int eval_queue_method_find_with(ivl_expr_t expr) /* First/last stop label: property path needs an extra pop. */ unsigned stop_lab = is_prop ? lab_found : lab_end; unsigned match_lab = multi ? lab_nom : stop_lab; + int as_index = queue_with_as_index(mode); + const char* new_empty = (is_string && !as_index) + ? "%queue/new_empty/str" + : "%queue/new_empty/v"; if (is_prop) { ivl_signal_t cl = ivl_expr_signal(qarg); @@ -638,7 +724,7 @@ static int eval_queue_method_find_with(ivl_expr_t expr) fprintf(vvp_out, " %%prop/queue/size %u;\n", pidx); fprintf(vvp_out, " %%ix/vec4/s %d;\n", n_reg); if (multi) { - fprintf(vvp_out, " %%queue/new_empty/v;\n"); + fprintf(vvp_out, " %s;\n", new_empty); } emit_queue_with_init_index(reverse, i_reg, n_reg); fprintf(vvp_out, "T_%u.%u ; queue with loop\n", thread_count, lab_top); @@ -652,18 +738,27 @@ static int eval_queue_method_find_with(ivl_expr_t expr) fprintf(vvp_out, " %%queue/size/v v%p_0;\n", sig); fprintf(vvp_out, " %%ix/vec4/s %d;\n", n_reg); if (multi) { - fprintf(vvp_out, " %%queue/new_empty/v;\n"); + fprintf(vvp_out, " %s;\n", new_empty); } emit_queue_with_init_index(reverse, i_reg, n_reg); fprintf(vvp_out, "T_%u.%u ; queue with loop (var)\n", thread_count, lab_top); emit_queue_with_loop_test(reverse, i_reg, n_reg, lab_loop_end); fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); - fprintf(vvp_out, " %%queue/word/v v%p_0, %u, %d;\n", sig, elem_wid, - i_reg); + if (is_string) { + fprintf(vvp_out, " %%ix/mov 3, %d;\n", i_reg); + fprintf(vvp_out, " %%load/dar/str v%p_0;\n", sig); + } else { + fprintf(vvp_out, " %%queue/word/v v%p_0, %u, %d;\n", sig, elem_wid, + i_reg); + } } - fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", item_sig, elem_wid); + if (is_string) { + fprintf(vvp_out, " %%store/str v%p_0;\n", item_sig); + } else { + fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", item_sig, elem_wid); + } fprintf(vvp_out, " %%push/ix/vec4 %d, 32, 1;\n", i_reg); fprintf(vvp_out, " %%store/vec4 v%p_0, 0, 32;\n", idx_sig); @@ -675,7 +770,8 @@ static int eval_queue_method_find_with(ivl_expr_t expr) int pf = draw_eval_condition(pred); fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count, lab_nom, pf); clr_flag(pf); - emit_queue_with_on_match(mode, item_sig, i_reg, elem_wid, match_lab); + emit_queue_with_on_match(mode, item_sig, i_reg, elem_wid, match_lab, + is_string); } fprintf(vvp_out, "T_%u.%u ; nomatch\n", thread_count, lab_nom); @@ -689,12 +785,12 @@ static int eval_queue_method_find_with(ivl_expr_t expr) fprintf(vvp_out, "T_%u.%u ; loop end (prop)\n", thread_count, lab_loop_end); - emit_queue_with_finish(mode, 1, elem_wid); + emit_queue_with_finish(mode, 1, elem_wid, is_string); fprintf(vvp_out, "T_%u.%u ; with end (prop)\n", thread_count, lab_end); } else { fprintf(vvp_out, "T_%u.%u ; loop end (var)\n", thread_count, lab_loop_end); - emit_queue_with_finish(mode, 0, elem_wid); + emit_queue_with_finish(mode, 0, elem_wid, is_string); fprintf(vvp_out, "T_%u.%u ; with end (var)\n", thread_count, lab_end); } diff --git a/tgt-vvp/eval_vec4.c b/tgt-vvp/eval_vec4.c index 6d97567de..bfffeb22b 100644 --- a/tgt-vvp/eval_vec4.c +++ b/tgt-vvp/eval_vec4.c @@ -1131,13 +1131,23 @@ static void draw_sfunc_vec4(ivl_expr_t expr) } if ((strcmp(ivl_expr_name(expr), "$ivl_queue_method$sum") == 0 || - strcmp(ivl_expr_name(expr), "$ivl_queue_method$product") == 0) && + strcmp(ivl_expr_name(expr), "$ivl_queue_method$product") == 0 || + strcmp(ivl_expr_name(expr), "$ivl_queue_method$and") == 0 || + strcmp(ivl_expr_name(expr), "$ivl_queue_method$or") == 0 || + strcmp(ivl_expr_name(expr), "$ivl_queue_method$xor") == 0) && parm_count == 1) { ivl_expr_t arg = ivl_expr_parm(expr, 0); unsigned wid = ivl_expr_width(expr); - const char* op = strcmp(ivl_expr_name(expr), "$ivl_queue_method$product") == 0 - ? "product" - : "sum"; + const char* name = ivl_expr_name(expr); + const char* op = "sum"; + if (strcmp(name, "$ivl_queue_method$product") == 0) + op = "product"; + else if (strcmp(name, "$ivl_queue_method$and") == 0) + op = "and"; + else if (strcmp(name, "$ivl_queue_method$or") == 0) + op = "or"; + else if (strcmp(name, "$ivl_queue_method$xor") == 0) + op = "xor"; if (ivl_expr_type(arg) == IVL_EX_PROPERTY) { ivl_signal_t clas = ivl_expr_signal(arg); unsigned pidx = ivl_expr_property_idx(arg); diff --git a/vvp/codes.h b/vvp/codes.h index fa3c2e73f..9e393a667 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -258,8 +258,16 @@ extern bool of_QPOP_PROP_F_REAL(vthread_t thr, vvp_code_t code); extern bool of_QPOP_PROP_F_STR(vthread_t thr, vvp_code_t code); extern bool of_QPOP_PROP_F_V(vthread_t thr, vvp_code_t code); extern bool of_PROP_QUEUE_SIZE(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_AND_OBJ_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_AND_PROP_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_AND_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_APPEND_WORD_STR(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_APPEND_WORD_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_NEW_EMPTY_STR(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_NEW_EMPTY_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_OR_OBJ_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_OR_PROP_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_OR_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_PRODUCT_PROP_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_PRODUCT_OBJ_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_PRODUCT_V(vthread_t thr, vvp_code_t code); @@ -269,6 +277,9 @@ extern bool of_QUEUE_SUM_PROP_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_SUM_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_WORD_PROP_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_WORD_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_XOR_OBJ_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_XOR_PROP_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_XOR_V(vthread_t thr, vvp_code_t code); extern bool of_CMPIX_LTU(vthread_t thr, vvp_code_t code); extern bool of_CMPIX_SLT0(vthread_t thr, vvp_code_t code); extern bool of_PUSH_IX_VEC4(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 8fdce1abf..72d31200d 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -279,6 +279,10 @@ static const struct opcode_table_s opcode_table[] = { { "%qpop/prop/f/r", of_QPOP_PROP_F_REAL, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%qpop/prop/f/str", of_QPOP_PROP_F_STR, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%qpop/prop/f/v", of_QPOP_PROP_F_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%queue/and/obj/v", of_QUEUE_AND_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} }, + { "%queue/and/prop/v", of_QUEUE_AND_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%queue/and/v", of_QUEUE_AND_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%queue/append_word/str", of_QUEUE_APPEND_WORD_STR, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%queue/append_word/v", of_QUEUE_APPEND_WORD_V, 1, {OA_BIT1, OA_NONE, OA_NONE} }, { "%queue/find/index/prop/v", of_QUEUE_FIND_INDEX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, { "%queue/find/index/v", of_QUEUE_FIND_INDEX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, @@ -298,7 +302,11 @@ static const struct opcode_table_s opcode_table[] = { { "%queue/min/obj/v", of_QUEUE_MIN_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} }, { "%queue/min/prop/v", of_QUEUE_MIN_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, { "%queue/min/v", of_QUEUE_MIN_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%queue/new_empty/str", of_QUEUE_NEW_EMPTY_STR, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%queue/new_empty/v", of_QUEUE_NEW_EMPTY_V, 0, {OA_NONE, OA_NONE, OA_NONE} }, + { "%queue/or/obj/v", of_QUEUE_OR_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} }, + { "%queue/or/prop/v", of_QUEUE_OR_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%queue/or/v", of_QUEUE_OR_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, { "%queue/product/obj/v", of_QUEUE_PRODUCT_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} }, { "%queue/product/prop/v", of_QUEUE_PRODUCT_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, { "%queue/product/v", of_QUEUE_PRODUCT_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, @@ -314,6 +322,9 @@ static const struct opcode_table_s opcode_table[] = { { "%queue/unique/v", of_QUEUE_UNIQUE_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, { "%queue/word/prop/v", of_QUEUE_WORD_PROP_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} }, { "%queue/word/v", of_QUEUE_WORD_V, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, + { "%queue/xor/obj/v", of_QUEUE_XOR_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} }, + { "%queue/xor/prop/v", of_QUEUE_XOR_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%queue/xor/v", of_QUEUE_XOR_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, { "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%release/wr", of_RELEASE_WR, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} }, diff --git a/vvp/vthread.cc b/vvp/vthread.cc index b70a81334..8170c2d17 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -6551,6 +6551,45 @@ static vvp_vector4_t queue_product_words_src(SRC* src, unsigned wid) return acc; } +template +static vvp_vector4_t queue_and_words_src(SRC* src, unsigned wid) +{ + vvp_vector4_t acc(wid, BIT4_1); + if (!src) return acc; + for (size_t i = 0; i < src->get_size(); i += 1) { + vvp_vector4_t vi(wid); + src->get_word(i, vi); + acc &= vi; + } + return acc; +} + +template +static vvp_vector4_t queue_or_words_src(SRC* src, unsigned wid) +{ + vvp_vector4_t acc(wid, BIT4_0); + if (!src) return acc; + for (size_t i = 0; i < src->get_size(); i += 1) { + vvp_vector4_t vi(wid); + src->get_word(i, vi); + acc |= vi; + } + return acc; +} + +template +static vvp_vector4_t queue_xor_words_src(SRC* src, unsigned wid) +{ + vvp_vector4_t acc(wid, BIT4_0); + if (!src) return acc; + for (size_t i = 0; i < src->get_size(); i += 1) { + vvp_vector4_t vi(wid); + src->get_word(i, vi); + acc ^= vi; + } + return acc; +} + bool of_QUEUE_PRODUCT_V(vthread_t thr, vvp_code_t cp) { vvp_net_t* net = cp->net; @@ -6663,6 +6702,174 @@ bool of_QUEUE_SUM_OBJ_V(vthread_t thr, vvp_code_t cp) return true; } +bool of_QUEUE_AND_V(vthread_t thr, vvp_code_t cp) +{ + vvp_net_t* net = cp->net; + unsigned wid = cp->bit_idx[0]; + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_net(thr, net, qsrc, dsrc); + vvp_vector4_t acc; + if (qsrc) acc = queue_and_words_src(qsrc, wid); + else if (dsrc) acc = queue_and_words_src(dsrc, wid); + else { + vvp_queue* src_q = get_queue_object(thr, net); + vvp_queue_vec4* src = dynamic_cast(src_q); + acc = queue_and_words_src(src, wid); + } + thr->push_vec4(acc); + return true; +} + +bool of_QUEUE_AND_PROP_V(vthread_t thr, vvp_code_t cp) +{ + size_t pid = cp->number; + unsigned wid = cp->bit_idx[0]; + + vvp_object_t& top = thr->peek_object(); + vvp_cobject*cobj = top.peek(); + assert(cobj); + + vvp_object_t qobj; + cobj->get_object(pid, qobj, 0); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); + vvp_vector4_t acc = + qsrc ? queue_and_words_src(qsrc, wid) + : queue_and_words_src(dsrc, wid); + thr->push_vec4(acc); + return true; +} + +bool of_QUEUE_AND_OBJ_V(vthread_t thr, vvp_code_t cp) +{ + unsigned wid = cp->bit_idx[0]; + vvp_object_t src_obj; + thr->pop_object(src_obj); + + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(src_obj, qsrc, dsrc); + vvp_vector4_t acc = + qsrc ? queue_and_words_src(qsrc, wid) + : queue_and_words_src(dsrc, wid); + thr->push_vec4(acc); + return true; +} + +bool of_QUEUE_OR_V(vthread_t thr, vvp_code_t cp) +{ + vvp_net_t* net = cp->net; + unsigned wid = cp->bit_idx[0]; + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_net(thr, net, qsrc, dsrc); + vvp_vector4_t acc; + if (qsrc) acc = queue_or_words_src(qsrc, wid); + else if (dsrc) acc = queue_or_words_src(dsrc, wid); + else { + vvp_queue* src_q = get_queue_object(thr, net); + vvp_queue_vec4* src = dynamic_cast(src_q); + acc = queue_or_words_src(src, wid); + } + thr->push_vec4(acc); + return true; +} + +bool of_QUEUE_OR_PROP_V(vthread_t thr, vvp_code_t cp) +{ + size_t pid = cp->number; + unsigned wid = cp->bit_idx[0]; + + vvp_object_t& top = thr->peek_object(); + vvp_cobject*cobj = top.peek(); + assert(cobj); + + vvp_object_t qobj; + cobj->get_object(pid, qobj, 0); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); + vvp_vector4_t acc = + qsrc ? queue_or_words_src(qsrc, wid) + : queue_or_words_src(dsrc, wid); + thr->push_vec4(acc); + return true; +} + +bool of_QUEUE_OR_OBJ_V(vthread_t thr, vvp_code_t cp) +{ + unsigned wid = cp->bit_idx[0]; + vvp_object_t src_obj; + thr->pop_object(src_obj); + + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(src_obj, qsrc, dsrc); + vvp_vector4_t acc = + qsrc ? queue_or_words_src(qsrc, wid) + : queue_or_words_src(dsrc, wid); + thr->push_vec4(acc); + return true; +} + +bool of_QUEUE_XOR_V(vthread_t thr, vvp_code_t cp) +{ + vvp_net_t* net = cp->net; + unsigned wid = cp->bit_idx[0]; + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_net(thr, net, qsrc, dsrc); + vvp_vector4_t acc; + if (qsrc) acc = queue_xor_words_src(qsrc, wid); + else if (dsrc) acc = queue_xor_words_src(dsrc, wid); + else { + vvp_queue* src_q = get_queue_object(thr, net); + vvp_queue_vec4* src = dynamic_cast(src_q); + acc = queue_xor_words_src(src, wid); + } + thr->push_vec4(acc); + return true; +} + +bool of_QUEUE_XOR_PROP_V(vthread_t thr, vvp_code_t cp) +{ + size_t pid = cp->number; + unsigned wid = cp->bit_idx[0]; + + vvp_object_t& top = thr->peek_object(); + vvp_cobject*cobj = top.peek(); + assert(cobj); + + vvp_object_t qobj; + cobj->get_object(pid, qobj, 0); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); + vvp_vector4_t acc = + qsrc ? queue_xor_words_src(qsrc, wid) + : queue_xor_words_src(dsrc, wid); + thr->push_vec4(acc); + return true; +} + +bool of_QUEUE_XOR_OBJ_V(vthread_t thr, vvp_code_t cp) +{ + unsigned wid = cp->bit_idx[0]; + vvp_object_t src_obj; + thr->pop_object(src_obj); + + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(src_obj, qsrc, dsrc); + vvp_vector4_t acc = + qsrc ? queue_xor_words_src(qsrc, wid) + : queue_xor_words_src(dsrc, wid); + thr->push_vec4(acc); + return true; +} + bool of_QUEUE_FIND_V(vthread_t thr, vvp_code_t cp) { vvp_vector4_t cmp = thr->pop_vec4(); @@ -7343,12 +7550,30 @@ bool of_PUSH_IX_VEC4(vthread_t thr, vvp_code_t cp) return true; } +bool of_QUEUE_NEW_EMPTY_STR(vthread_t thr, vvp_code_t) +{ + thr->push_object(vvp_object_t(new vvp_queue_string())); + return true; +} + bool of_QUEUE_NEW_EMPTY_V(vthread_t thr, vvp_code_t) { thr->push_object(vvp_object_t(new vvp_queue_vec4())); return true; } +bool of_QUEUE_APPEND_WORD_STR(vthread_t thr, vvp_code_t) +{ + string elem = thr->pop_str(); + vvp_object_t qobj; + thr->pop_object(qobj); + vvp_queue_string* q = qobj.peek(); + assert(q); + q->push_back(elem, 0); + thr->push_object(qobj); + return true; +} + bool of_QUEUE_APPEND_WORD_V(vthread_t thr, vvp_code_t cp) { unsigned wid = cp->bit_idx[0];