From e628e6c8c58d2177471fff099592a8f0086ccc3f Mon Sep 17 00:00:00 2001 From: mjoekhan Date: Wed, 1 Jul 2026 12:45:16 +0500 Subject: [PATCH] SV: sum() and product() reductions on queues/darrays Add integral sum() and product() reductions, including expression forms, for queues, dynamic arrays, and class properties. Split from steveicarus/iverilog#1330 (part 05/6). --- elab_expr.cc | 213 ++++++++++++++++-- .../ivltests/sv_class_darray_prop_locators.v | 3 + .../ivltests/sv_class_queue_prop_locators.v | 58 +++++ ivtest/ivltests/sv_darray_product.v | 24 ++ ivtest/ivltests/sv_darray_product_with.v | 24 ++ ivtest/ivltests/sv_darray_sum.v | 28 +++ ivtest/ivltests/sv_darray_sum_with.v | 24 ++ ivtest/ivltests/sv_queue_product.v | 24 ++ ivtest/ivltests/sv_queue_product_with.v | 24 ++ ivtest/ivltests/sv_queue_sum.v | 28 +++ ivtest/ivltests/sv_queue_sum_with.v | 24 ++ ivtest/regress-vvp.list | 9 + .../sv_class_queue_prop_locators.json | 9 + ivtest/vvp_tests/sv_darray_product.json | 9 + ivtest/vvp_tests/sv_darray_product_with.json | 9 + ivtest/vvp_tests/sv_darray_sum.json | 9 + ivtest/vvp_tests/sv_darray_sum_with.json | 9 + ivtest/vvp_tests/sv_queue_product.json | 9 + ivtest/vvp_tests/sv_queue_product_with.json | 9 + ivtest/vvp_tests/sv_queue_sum.json | 9 + ivtest/vvp_tests/sv_queue_sum_with.json | 9 + tgt-vvp/eval_object.c | 108 +++++++-- tgt-vvp/eval_vec4.c | 22 ++ vvp/codes.h | 6 + vvp/compile.cc | 8 +- vvp/vthread.cc | 139 ++++++++++++ 26 files changed, 810 insertions(+), 37 deletions(-) create mode 100644 ivtest/ivltests/sv_class_queue_prop_locators.v create mode 100644 ivtest/ivltests/sv_darray_product.v create mode 100644 ivtest/ivltests/sv_darray_product_with.v create mode 100644 ivtest/ivltests/sv_darray_sum.v create mode 100644 ivtest/ivltests/sv_darray_sum_with.v create mode 100644 ivtest/ivltests/sv_queue_product.v create mode 100644 ivtest/ivltests/sv_queue_product_with.v create mode 100644 ivtest/ivltests/sv_queue_sum.v create mode 100644 ivtest/ivltests/sv_queue_sum_with.v create mode 100644 ivtest/vvp_tests/sv_class_queue_prop_locators.json create mode 100644 ivtest/vvp_tests/sv_darray_product.json create mode 100644 ivtest/vvp_tests/sv_darray_product_with.json create mode 100644 ivtest/vvp_tests/sv_darray_sum.json create mode 100644 ivtest/vvp_tests/sv_darray_sum_with.json create mode 100644 ivtest/vvp_tests/sv_queue_product.json create mode 100644 ivtest/vvp_tests/sv_queue_product_with.json create mode 100644 ivtest/vvp_tests/sv_queue_sum.json create mode 100644 ivtest/vvp_tests/sv_queue_sum_with.json diff --git a/elab_expr.cc b/elab_expr.cc index c7beda3b8..5b8a3c99c 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -105,8 +105,14 @@ static NetExpr* elab_queue_locator_with_predicate( index_net->set_line(loc); index_net->local_flag(true); - NetExpr* pred = elab_and_eval(des, ws, with_expr, 1, false, false, - IVL_VT_BOOL); + NetExpr* pred = 0; + if (method_suffix == "sum" || method_suffix == "product") { + pred = elab_and_eval(des, ws, with_expr, (int)ew, false, false, + ivl_type_base(element_type)); + } else { + pred = elab_and_eval(des, ws, with_expr, 1, false, false, + IVL_VT_BOOL); + } if (!pred) return 0; perm_string sfunc_name; @@ -130,6 +136,10 @@ static NetExpr* elab_queue_locator_with_predicate( sfunc_name = lex_strings.make("$ivl_queue_method$min_with"); } else if (method_suffix == "max") { sfunc_name = lex_strings.make("$ivl_queue_method$max_with"); + } else if (method_suffix == "sum") { + 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 { ivl_assert(loc, 0); } @@ -225,6 +235,58 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope, return sys_expr; } +static bool is_array_reduction_method(perm_string name) +{ + return name == "sum" || name == "product"; +} + +/* + * Elaborate sum()/product() on a queue or dynamic array expression. + * Returns an integral value with the element type/width. + */ +static NetExpr* elab_array_reduction_method(Design* des, NetScope* scope, + const LineInfo& loc, + perm_string method_name, + NetExpr* array_arg, + ivl_type_t element_type, + const vector& parms, + PExpr* with_expr, const char* kind) +{ + 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; + } + + char sfunc[64]; + snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s", method_name.str()); + + if (with_expr) { + if (!parms.empty()) { + cerr << loc.get_fileline() << ": error: array locator " + << "`with` clause cannot be combined with a " + << "method argument." << endl; + des->errors += 1; + return 0; + } + return elab_queue_locator_with_predicate(des, scope, loc, with_expr, + array_arg, element_type, + element_type, method_name); + } + + if (parms.size() != 0) { + cerr << loc.get_fileline() << ": error: " << method_name + << "() method takes no arguments" << endl; + des->errors += 1; + } + NetESFunc*sys_expr = new NetESFunc(sfunc, element_type, 1); + sys_expr->set_line(loc); + sys_expr->parm(0, array_arg); + return sys_expr; +} + bool type_is_vectorable(ivl_variable_type_t type) { switch (type) { @@ -1830,6 +1892,21 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*, return expr_width_; } + if (method_name == "sum") { + expr_type_ = darray->element_base_type(); + expr_width_ = darray->element_width(); + min_width_ = expr_width_; + signed_flag_ = darray->get_signed(); + return expr_width_; + } + if (method_name == "product") { + expr_type_ = darray->element_base_type(); + expr_width_ = darray->element_width(); + min_width_ = expr_width_; + signed_flag_ = darray->get_signed(); + return expr_width_; + } + if (method_name == "find" || method_name == "find_index" || method_name == "unique" || method_name == "unique_index" || method_name == "min" || method_name == "max") { @@ -1887,6 +1964,21 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*, return expr_width_; } + if (method_name == "sum") { + expr_type_ = darray->element_base_type(); + expr_width_ = darray->element_width(); + min_width_ = expr_width_; + signed_flag_ = darray->get_signed(); + return expr_width_; + } + if (method_name == "product") { + expr_type_ = darray->element_base_type(); + expr_width_ = darray->element_width(); + min_width_ = expr_width_; + signed_flag_ = darray->get_signed(); + return expr_width_; + } + if (method_name == "unique" || method_name == "unique_index" || method_name == "min" || method_name == "max" || method_name == "find" || method_name == "find_index") { @@ -3838,8 +3930,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, static_cast(queue), parms_, with_expr_, "queue"); } + if (is_array_reduction_method(method_name)) { + return elab_array_reduction_method(des, scope, *this, + method_name, prop, element_type, + parms_, with_expr_, "queue"); + } } - if (ptype && ptype->base_type() == IVL_VT_DARRAY) { + if (ptype && + (ptype->base_type() == IVL_VT_DARRAY || + ptype->base_type() == IVL_VT_QUEUE)) { NetEProperty*prop = new NetEProperty(search_results.net, pidx, nullptr); prop->set_line(*this); perm_string method_name = search_results.path_tail.back().name; @@ -3859,7 +3958,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, return elab_array_locator_method(des, scope, *this, method_name, prop, element_type, ptype, parms_, with_expr_, - "dynamic array"); + "array"); + } + if (is_array_reduction_method(method_name)) { + return elab_array_reduction_method(des, scope, *this, + method_name, prop, element_type, + parms_, with_expr_, "array"); } } } @@ -3968,6 +4072,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, queue_rtype, parms_, with_expr_, "dynamic array"); } + if (is_array_reduction_method(method_name)) { + return elab_array_reduction_method(des, scope, *this, method_name, + sub_expr, element_type, + parms_, with_expr_, + "dynamic array"); + } cerr << get_fileline() << ": error: Method " << method_name << " is not a dynamic array method." << endl; @@ -4027,6 +4137,11 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, static_cast(queue), parms_, with_expr_, "queue"); } + if (is_array_reduction_method(method_name)) { + return elab_array_reduction_method(des, scope, *this, method_name, + sub_expr, element_type, + parms_, with_expr_, "queue"); + } cerr << get_fileline() << ": error: Method " << method_name << " is not a queue method." << endl; @@ -5252,6 +5367,38 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, fun->parm(0, arg); return fun; } + if (member_comp.name == "sum") { + if (!queue_method_element_is_integral_vec4(element_type)) { + cerr << get_fileline() << ": sorry: queue 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; + } + if (member_comp.name == "product") { + if (!queue_method_element_is_integral_vec4(element_type)) { + cerr << get_fileline() << ": sorry: queue 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; + } 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 @@ -5586,6 +5733,22 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, fun->parm(0, arg); return fun; } + if (member_comp.name == "sum") { + if (!queue_method_element_is_integral_vec4(element_type)) { + cerr << get_fileline() << ": sorry: queue 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; + } 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 @@ -5666,17 +5829,39 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, return 0; // FIXME: Check this is a real or integral type. } else if (member_comp.name == "sum") { - cerr << get_fileline() << ": sorry: 'sum()' " - "array reduction method is not currently " - "implemented." << endl; - des->errors += 1; - return 0; + 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") { - cerr << get_fileline() << ": sorry: 'product()' " - "array reduction method is not currently " - "implemented." << endl; - des->errors += 1; - return 0; + 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()' " diff --git a/ivtest/ivltests/sv_class_darray_prop_locators.v b/ivtest/ivltests/sv_class_darray_prop_locators.v index 5f7da3ec7..7458e8ffe 100644 --- a/ivtest/ivltests/sv_class_darray_prop_locators.v +++ b/ivtest/ivltests/sv_class_darray_prop_locators.v @@ -57,6 +57,9 @@ module test; `check(r.size, 1); `check(r[0], 6); + c.d = '{2, 3, 4}; + `check(c.d.product(), 24); + if (!failed) $display("PASSED"); end diff --git a/ivtest/ivltests/sv_class_queue_prop_locators.v b/ivtest/ivltests/sv_class_queue_prop_locators.v new file mode 100644 index 000000000..c6e5adf0b --- /dev/null +++ b/ivtest/ivltests/sv_class_queue_prop_locators.v @@ -0,0 +1,58 @@ +// Regression: class queue property locator methods. + +module test; + + bit failed = 1'b0; + + `define check(val, exp) do if ((val) !== (exp)) begin $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); failed = 1'b1; end while (0) + + class C; + int q[$]; + endclass + + C c; + int r[$]; + + initial begin + c = new; + c.q = '{4, 7, 2, 5, 7, 1, 6, 3, 1}; + + r = c.q.find() with (item > 3); + `check(r.size, 5); + `check(r[0], 4); + `check(r[4], 6); + + r = c.q.find_last_index() with (item < 3); + `check(r.size, 1); + `check(r[0], 8); + + r = c.q.unique() with (item > 2); + `check(r.size, 5); + `check(r[0], 4); + `check(r[4], 3); + + r = c.q.unique_index() with (item > 2); + `check(r.size, 6); + `check(r[0], 0); + `check(r[5], 7); + + r = c.q.min(); + `check(r.size, 2); + `check(r[0], 1); + `check(r[1], 1); + + r = c.q.max() with (item < 7); + `check(r.size, 1); + `check(r[0], 6); + + r = c.q.max(); + `check(r.size, 2); + `check(r[0], 7); + + c.q = '{2, 3, 4}; + `check(c.q.product(), 24); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_darray_product.v b/ivtest/ivltests/sv_darray_product.v new file mode 100644 index 000000000..e9a35181c --- /dev/null +++ b/ivtest/ivltests/sv_darray_product.v @@ -0,0 +1,24 @@ +// Regression: dynamic array product() reduction (integral). + +module top; + + bit failed = 0; + + `define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end + + int a[]; + int p; + + initial begin + a = '{2, 3, 4}; + p = a.product(); + `CHK(p === 24); + + a = '{-2, 3, 5}; + p = a.product(); + `CHK(p === -30); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_darray_product_with.v b/ivtest/ivltests/sv_darray_product_with.v new file mode 100644 index 000000000..11a706468 --- /dev/null +++ b/ivtest/ivltests/sv_darray_product_with.v @@ -0,0 +1,24 @@ +// Regression: dynamic array product() reduction with expression. + +module top; + + bit failed = 0; + + `define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end + + int a[]; + int p; + + initial begin + a = '{10, -3, 5}; + + p = a.product() with (item > 0); + `CHK(p === 0); + + p = a.product() with (item + 1); + `CHK(p === -132); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_darray_sum.v b/ivtest/ivltests/sv_darray_sum.v new file mode 100644 index 000000000..0ae6986fe --- /dev/null +++ b/ivtest/ivltests/sv_darray_sum.v @@ -0,0 +1,28 @@ +// Regression: dynamic array sum() reduction (integral). + +module top; + + bit failed = 0; + + `define CHK(cond) \ + if (!(cond)) begin \ + $display("FAILED line %0d", `__LINE__); \ + failed = 1; \ + end + + int a[]; + int s; + + initial begin + a = new[0]; + s = a.sum(); + `CHK(s === 0); + + a = '{10, -3, 5}; + s = a.sum(); + `CHK(s === 12); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_darray_sum_with.v b/ivtest/ivltests/sv_darray_sum_with.v new file mode 100644 index 000000000..4616821e1 --- /dev/null +++ b/ivtest/ivltests/sv_darray_sum_with.v @@ -0,0 +1,24 @@ +// Regression: dynamic array sum() reduction with expression. + +module top; + + bit failed = 0; + + `define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end + + int a[]; + int s; + + initial begin + a = '{10, -3, 5}; + + s = a.sum() with (item > 0); + `CHK(s === 2); + + s = a.sum() with (item + 1); + `CHK(s === 15); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_product.v b/ivtest/ivltests/sv_queue_product.v new file mode 100644 index 000000000..28dbe3f27 --- /dev/null +++ b/ivtest/ivltests/sv_queue_product.v @@ -0,0 +1,24 @@ +// Regression: queue product() reduction (integral). + +module top; + + bit failed = 0; + + `define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end + + int q[$]; + int p; + + initial begin + q = '{2, 3, 4}; + p = q.product(); + `CHK(p === 24); + + q = '{-2, 3, 5}; + p = q.product(); + `CHK(p === -30); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_product_with.v b/ivtest/ivltests/sv_queue_product_with.v new file mode 100644 index 000000000..62af05150 --- /dev/null +++ b/ivtest/ivltests/sv_queue_product_with.v @@ -0,0 +1,24 @@ +// Regression: queue product() reduction with expression. + +module top; + + bit failed = 0; + + `define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end + + int q[$]; + int p; + + initial begin + q = '{4, 7, 2}; + + p = q.product() with (item > 3); + `CHK(p === 0); + + p = q.product() with (item + 1); + `CHK(p === 120); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_sum.v b/ivtest/ivltests/sv_queue_sum.v new file mode 100644 index 000000000..49baa17ee --- /dev/null +++ b/ivtest/ivltests/sv_queue_sum.v @@ -0,0 +1,28 @@ +// Regression: queue sum() reduction (integral). + +module top; + + bit failed = 0; + + `define CHK(cond) \ + if (!(cond)) begin \ + $display("FAILED line %0d", `__LINE__); \ + failed = 1; \ + end + + int q[$]; + int s; + + initial begin + q = '{}; + s = q.sum(); + `CHK(s === 0); + + q = '{4, 7, 2}; + s = q.sum(); + `CHK(s === 13); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_sum_with.v b/ivtest/ivltests/sv_queue_sum_with.v new file mode 100644 index 000000000..907173c8e --- /dev/null +++ b/ivtest/ivltests/sv_queue_sum_with.v @@ -0,0 +1,24 @@ +// Regression: queue sum() reduction with expression. + +module top; + + bit failed = 0; + + `define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end + + int q[$]; + int s; + + initial begin + q = '{4, 7, 2, 5}; + + s = q.sum() with (item > 3); + `CHK(s === 3); + + s = q.sum() with (item * 2); + `CHK(s === 36); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 35f4ec74f..7fd80304e 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -291,6 +291,7 @@ sv_class_darray_prop_locators vvp_tests/sv_class_darray_prop_locators.json sv_class_prop_packed_dims vvp_tests/sv_class_prop_packed_dims.json sv_class_prop_type_name vvp_tests/sv_class_prop_type_name.json sv_class_prop_wildcard_type_name vvp_tests/sv_class_prop_wildcard_type_name.json +sv_class_queue_prop_locators vvp_tests/sv_class_queue_prop_locators.json sv_class_prop_nest_darray1 vvp_tests/sv_class_prop_nest_darray1.json sv_class_prop_nest_obj1 vvp_tests/sv_class_prop_nest_obj1.json sv_class_prop_nest_real1 vvp_tests/sv_class_prop_nest_real1.json @@ -316,6 +317,10 @@ sv_darray_assign_op vvp_tests/sv_darray_assign_op.json sv_darray_find_locators vvp_tests/sv_darray_find_locators.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 +sv_darray_product_with vvp_tests/sv_darray_product_with.json +sv_darray_sum vvp_tests/sv_darray_sum.json +sv_darray_sum_with vvp_tests/sv_darray_sum_with.json sv_darray_unique vvp_tests/sv_darray_unique.json sv_darray_unique_with vvp_tests/sv_darray_unique_with.json sv_declaration_after_null_statement_fail vvp_tests/sv_declaration_after_null_statement_fail.json @@ -415,6 +420,10 @@ sv_queue_method_push_front_too_few_arg_fail vvp_tests/sv_queue_method_push_front sv_queue_method_push_front_too_many_arg_fail vvp_tests/sv_queue_method_push_front_too_many_arg_fail.json sv_queue_min_max vvp_tests/sv_queue_min_max.json sv_queue_min_max_with vvp_tests/sv_queue_min_max_with.json +sv_queue_product vvp_tests/sv_queue_product.json +sv_queue_product_with vvp_tests/sv_queue_product_with.json +sv_queue_sum vvp_tests/sv_queue_sum.json +sv_queue_sum_with vvp_tests/sv_queue_sum_with.json sv_queue_unique vvp_tests/sv_queue_unique.json sv_queue_unique_with vvp_tests/sv_queue_unique_with.json sv_soft_packed_union vvp_tests/sv_soft_packed_union.json diff --git a/ivtest/vvp_tests/sv_class_queue_prop_locators.json b/ivtest/vvp_tests/sv_class_queue_prop_locators.json new file mode 100644 index 000000000..cde66114a --- /dev/null +++ b/ivtest/vvp_tests/sv_class_queue_prop_locators.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_class_queue_prop_locators.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog class queue property locator methods", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_darray_product.json b/ivtest/vvp_tests/sv_darray_product.json new file mode 100644 index 000000000..75501c439 --- /dev/null +++ b/ivtest/vvp_tests/sv_darray_product.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_darray_product.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog dynamic array product() reduction", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_darray_product_with.json b/ivtest/vvp_tests/sv_darray_product_with.json new file mode 100644 index 000000000..2b838ed3f --- /dev/null +++ b/ivtest/vvp_tests/sv_darray_product_with.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_darray_product_with.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog dynamic array product() with expression", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_darray_sum.json b/ivtest/vvp_tests/sv_darray_sum.json new file mode 100644 index 000000000..844957ccc --- /dev/null +++ b/ivtest/vvp_tests/sv_darray_sum.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_darray_sum.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog dynamic array sum() reduction", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_darray_sum_with.json b/ivtest/vvp_tests/sv_darray_sum_with.json new file mode 100644 index 000000000..5146f2344 --- /dev/null +++ b/ivtest/vvp_tests/sv_darray_sum_with.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_darray_sum_with.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog dynamic array sum() with expression", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_queue_product.json b/ivtest/vvp_tests/sv_queue_product.json new file mode 100644 index 000000000..84bb5e979 --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_product.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_queue_product.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog queue product() reduction", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_queue_product_with.json b/ivtest/vvp_tests/sv_queue_product_with.json new file mode 100644 index 000000000..2ce9df377 --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_product_with.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_queue_product_with.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog queue product() with expression", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_queue_sum.json b/ivtest/vvp_tests/sv_queue_sum.json new file mode 100644 index 000000000..523bc9dee --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_sum.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_queue_sum.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog queue sum() reduction", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_queue_sum_with.json b/ivtest/vvp_tests/sv_queue_sum_with.json new file mode 100644 index 000000000..6ab5de32a --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_sum_with.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_queue_sum_with.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog queue sum() with expression", + "type" : "CE" + } +} diff --git a/tgt-vvp/eval_object.c b/tgt-vvp/eval_object.c index 13d4e6a98..abf21480b 100644 --- a/tgt-vvp/eval_object.c +++ b/tgt-vvp/eval_object.c @@ -173,33 +173,59 @@ static int eval_darray_new(ivl_expr_t ex) return errors; } -/* Build a dynamic-array object value from an array pattern expression. */ -static int eval_darray_pattern_object(ivl_expr_t ex) +/* Build a queue/dynamic-array object value from an array pattern expression. */ +static int eval_array_pattern_object(ivl_expr_t ex) { int errors = 0; ivl_type_t net_type = ivl_expr_net_type(ex); - if (!net_type || ivl_type_base(net_type) != IVL_VT_DARRAY) return 1; + if (!net_type) return 1; + ivl_variable_type_t base_type = ivl_type_base(net_type); + if (base_type != IVL_VT_DARRAY && base_type != IVL_VT_QUEUE) return 1; ivl_type_t element_type = ivl_type_element(net_type); if (!element_type) return 1; - unsigned size_reg = allocate_word(); - fprintf(vvp_out, " %%ix/load %u, %u, 0;\n", size_reg, ivl_expr_parms(ex)); - fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); - darray_new(element_type, size_reg); + unsigned max_elems = ivl_expr_parms(ex); + if (base_type == IVL_VT_QUEUE) { + unsigned max_size = ivl_type_queue_max(net_type); + if (max_size != 0 && max_elems > max_size) { + fprintf(stderr, "%s:%u: Warning: Array pattern assignment has more " + "elements (%u) than bounded queue supports (%u).\n" + " Only using first %u elements.\n", + ivl_expr_file(ex), ivl_expr_lineno(ex), max_elems, max_size, max_size); + max_elems = max_size; + } + fprintf(vvp_out, " %%queue/new_empty/v;\n"); + } else { + unsigned size_reg = allocate_word(); + fprintf(vvp_out, " %%ix/load %u, %u, 0;\n", size_reg, max_elems); + fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); + darray_new(element_type, size_reg); + } switch (ivl_type_base(element_type)) { case IVL_VT_BOOL: case IVL_VT_LOGIC: - for (unsigned idx = 0; idx < ivl_expr_parms(ex); idx += 1) { + for (unsigned idx = 0; idx < max_elems; idx += 1) { draw_eval_vec4(ivl_expr_parm(ex, idx)); - fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); - fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n"); - fprintf(vvp_out, " %%pop/vec4 1;\n"); + if (base_type == IVL_VT_QUEUE) { + fprintf(vvp_out, " %%queue/append_word/v %u;\n", + ivl_type_packed_width(element_type)); + } else { + fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); + fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n"); + fprintf(vvp_out, " %%pop/vec4 1;\n"); + } } break; case IVL_VT_REAL: - for (unsigned idx = 0; idx < ivl_expr_parms(ex); idx += 1) { + for (unsigned idx = 0; idx < max_elems; idx += 1) { + if (base_type == IVL_VT_QUEUE) { + fprintf(vvp_out, "; ERROR: eval_array_pattern_object: queue real " + "element type not implemented\n"); + errors += 1; + break; + } draw_eval_real(ivl_expr_parm(ex, idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); fprintf(vvp_out, " %%set/dar/obj/real 3;\n"); @@ -207,7 +233,13 @@ static int eval_darray_pattern_object(ivl_expr_t ex) } break; case IVL_VT_STRING: - for (unsigned idx = 0; idx < ivl_expr_parms(ex); idx += 1) { + for (unsigned idx = 0; idx < max_elems; idx += 1) { + if (base_type == IVL_VT_QUEUE) { + fprintf(vvp_out, "; ERROR: eval_array_pattern_object: queue string " + "element type not implemented\n"); + errors += 1; + break; + } draw_eval_string(ivl_expr_parm(ex, idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); fprintf(vvp_out, " %%set/dar/obj/str 3;\n"); @@ -215,7 +247,7 @@ static int eval_darray_pattern_object(ivl_expr_t ex) } break; default: - fprintf(vvp_out, "; ERROR: eval_darray_pattern_object: unsupported " + fprintf(vvp_out, "; ERROR: eval_array_pattern_object: unsupported " "element type %d\n", ivl_type_base(element_type)); errors += 1; break; @@ -397,7 +429,9 @@ enum queue_locator_with_mode_e { QUEUE_WITH_MIN, QUEUE_WITH_MAX, QUEUE_WITH_UNIQUE, - QUEUE_WITH_UNIQUE_INDEX + QUEUE_WITH_UNIQUE_INDEX, + QUEUE_WITH_SUM, + QUEUE_WITH_PRODUCT }; static enum queue_locator_with_mode_e queue_locator_with_mode_from_name( @@ -423,6 +457,10 @@ static enum queue_locator_with_mode_e queue_locator_with_mode_from_name( return QUEUE_WITH_UNIQUE; } else if (strcmp(name, "$ivl_queue_method$unique_index_with") == 0) { return QUEUE_WITH_UNIQUE_INDEX; + } else if (strcmp(name, "$ivl_queue_method$sum_with") == 0) { + return QUEUE_WITH_SUM; + } else if (strcmp(name, "$ivl_queue_method$product_with") == 0) { + return QUEUE_WITH_PRODUCT; } return (enum queue_locator_with_mode_e) -1; } @@ -440,7 +478,14 @@ static int queue_with_multi(enum queue_locator_with_mode_e mode) mode == QUEUE_WITH_MIN || mode == QUEUE_WITH_MAX || mode == QUEUE_WITH_UNIQUE || - mode == QUEUE_WITH_UNIQUE_INDEX; + mode == QUEUE_WITH_UNIQUE_INDEX || + mode == QUEUE_WITH_SUM || + mode == QUEUE_WITH_PRODUCT; +} + +static int queue_with_expr_value(enum queue_locator_with_mode_e mode) +{ + return mode == QUEUE_WITH_SUM || mode == QUEUE_WITH_PRODUCT; } static int queue_with_as_index(enum queue_locator_with_mode_e mode) @@ -527,6 +572,20 @@ static void emit_queue_with_finish(enum queue_locator_with_mode_e mode, } return; } + if (mode == QUEUE_WITH_SUM) { + fprintf(vvp_out, " %%queue/sum/obj/v %u;\n", elem_wid); + if (is_prop) { + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + } + return; + } + if (mode == QUEUE_WITH_PRODUCT) { + fprintf(vvp_out, " %%queue/product/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"); @@ -608,11 +667,16 @@ static int eval_queue_method_find_with(ivl_expr_t expr) 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); - 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); + if (queue_with_expr_value(mode)) { + draw_eval_vec4(pred); + fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid); + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom); + } else { + 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); + } fprintf(vvp_out, "T_%u.%u ; nomatch\n", thread_count, lab_nom); emit_queue_with_step_index(reverse, i_reg, lab_top); @@ -720,7 +784,7 @@ int draw_eval_object(ivl_expr_t ex) return eval_object_ufunc(ex); case IVL_EX_ARRAY_PATTERN: - return eval_darray_pattern_object(ex); + return eval_array_pattern_object(ex); case IVL_EX_SFUNC: /* Queue locator `with` may report IVL_VT_DARRAY in ivl; handle by name. */ diff --git a/tgt-vvp/eval_vec4.c b/tgt-vvp/eval_vec4.c index 623390e7a..6d97567de 100644 --- a/tgt-vvp/eval_vec4.c +++ b/tgt-vvp/eval_vec4.c @@ -1130,6 +1130,28 @@ 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) && + 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"; + if (ivl_expr_type(arg) == IVL_EX_PROPERTY) { + ivl_signal_t clas = ivl_expr_signal(arg); + unsigned pidx = ivl_expr_property_idx(arg); + fprintf(vvp_out, " %%load/obj v%p_0;\n", clas); + fprintf(vvp_out, " %%queue/%s/prop/v %u, %u;\n", op, pidx, wid); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + return; + } + assert(ivl_expr_type(arg) == IVL_EX_SIGNAL); + fprintf(vvp_out, " %%queue/%s/v v%p_0, %u;\n", + op, ivl_expr_signal(arg), wid); + return; + } + draw_vpi_func_call(expr); } diff --git a/vvp/codes.h b/vvp/codes.h index 963648e2c..65fe2b13b 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -252,7 +252,13 @@ 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_APPEND_WORD_V(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_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); extern bool of_QUEUE_SIZE_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_SUM_OBJ_V(vthread_t thr, vvp_code_t code); +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_CMPIX_LTU(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 9a3b11809..9fce0507f 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -52,7 +52,7 @@ unsigned compile_errors = 0; * by mnemonic string: compile_code() uses bsearch() on this array. * If the order is wrong, lookup fails and the assembler reports * "Invalid opcode" for otherwise valid instructions (e.g. class - * property queue ops must sort among all %delete/*, %qpop/*, %store/* + * property queue ops must sort among all %delete*, %qpop*, %store* * names, not grouped by feature). * The opcode_compare function is a helper for that lookup. */ @@ -299,7 +299,13 @@ static const struct opcode_table_s opcode_table[] = { { "%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/v", of_QUEUE_NEW_EMPTY_V, 0, {OA_NONE, OA_NONE, 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} }, { "%queue/size/v", of_QUEUE_SIZE_V, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, + { "%queue/sum/obj/v", of_QUEUE_SUM_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} }, + { "%queue/sum/prop/v", of_QUEUE_SUM_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%queue/sum/v", of_QUEUE_SUM_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, { "%queue/unique/index/obj/v", of_QUEUE_UNIQUE_INDEX_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} }, { "%queue/unique/index/prop/v", of_QUEUE_UNIQUE_INDEX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, { "%queue/unique/index/v", of_QUEUE_UNIQUE_INDEX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 61eacfdc4..185ad41c5 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -6326,6 +6326,145 @@ static vvp_queue_vec4* queue_run_min_max_src(SRC* src, unsigned wid, bool want_m return dst; } +/* sum() reduction returns the scalar sum (Verilog-style addition per word). */ +template +static vvp_vector4_t queue_sum_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.add(vi); + } + return acc; +} + +template +static vvp_vector4_t queue_product_words_src(SRC* src, unsigned wid) +{ + vvp_vector4_t acc = queue_unique_ulong_to_vec4(1UL, wid); + 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.mul(vi); + } + return acc; +} + +bool of_QUEUE_PRODUCT_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 prod; + if (qsrc) prod = queue_product_words_src(qsrc, wid); + else if (dsrc) prod = queue_product_words_src(dsrc, wid); + else { + vvp_queue* src_q = get_queue_object(thr, net); + vvp_queue_vec4* src = dynamic_cast(src_q); + prod = queue_product_words_src(src, wid); + } + thr->push_vec4(prod); + return true; +} + +bool of_QUEUE_PRODUCT_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 prod = + qsrc ? queue_product_words_src(qsrc, wid) + : queue_product_words_src(dsrc, wid); + thr->push_vec4(prod); + return true; +} + +bool of_QUEUE_PRODUCT_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 prod = + qsrc ? queue_product_words_src(qsrc, wid) + : queue_product_words_src(dsrc, wid); + thr->push_vec4(prod); + return true; +} + +bool of_QUEUE_SUM_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 sum; + if (qsrc) sum = queue_sum_words_src(qsrc, wid); + else if (dsrc) sum = queue_sum_words_src(dsrc, wid); + else { + vvp_queue* src_q = get_queue_object(thr, net); + vvp_queue_vec4* src = dynamic_cast(src_q); + sum = queue_sum_words_src(src, wid); + } + thr->push_vec4(sum); + return true; +} + +bool of_QUEUE_SUM_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 sum = + qsrc ? queue_sum_words_src(qsrc, wid) + : queue_sum_words_src(dsrc, wid); + thr->push_vec4(sum); + return true; +} + +bool of_QUEUE_SUM_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 sum = + qsrc ? queue_sum_words_src(qsrc, wid) + : queue_sum_words_src(dsrc, wid); + thr->push_vec4(sum); + return true; +} + bool of_QUEUE_FIND_V(vthread_t thr, vvp_code_t cp) { vvp_vector4_t cmp = thr->pop_vec4();