From 243dccc36844934e9f32caf5a01f490a6e77e36f Mon Sep 17 00:00:00 2001 From: mjoekhan Date: Mon, 20 Jul 2026 20:41:19 +0500 Subject: [PATCH] SV: locator methods on class queue/darray properties Extend locator methods to class queue and dynamic-array properties, including min/max, unique/min/max with-predicates, and VVP array-pattern object handling. Built on the #1419 locator helpers. Split from steveicarus/iverilog#1330 (part 04/6). --- elab_expr.cc | 93 ++++-- .../ivltests/sv_class_darray_prop_locators.v | 63 ++++ ivtest/ivltests/sv_darray_min_max.v | 36 ++ ivtest/ivltests/sv_darray_min_max_with.v | 30 ++ ivtest/ivltests/sv_darray_unique.v | 29 ++ ivtest/ivltests/sv_darray_unique_with.v | 33 ++ ivtest/ivltests/sv_queue_min_max.v | 47 +++ ivtest/ivltests/sv_queue_min_max_with.v | 41 +++ ivtest/ivltests/sv_queue_unique_with.v | 35 ++ ivtest/regress-vvp.list | 8 + .../sv_class_darray_prop_locators.json | 10 + ivtest/vvp_tests/sv_darray_min_max.json | 9 + ivtest/vvp_tests/sv_darray_min_max_with.json | 9 + ivtest/vvp_tests/sv_darray_unique.json | 9 + ivtest/vvp_tests/sv_darray_unique_with.json | 9 + ivtest/vvp_tests/sv_queue_min_max.json | 9 + ivtest/vvp_tests/sv_queue_min_max_with.json | 9 + ivtest/vvp_tests/sv_queue_unique_with.json | 9 + tgt-vvp/eval_object.c | 128 ++++++- vvp/codes.h | 8 + vvp/compile.cc | 10 +- vvp/vthread.cc | 313 +++++++++++++++--- 22 files changed, 873 insertions(+), 74 deletions(-) create mode 100644 ivtest/ivltests/sv_class_darray_prop_locators.v create mode 100644 ivtest/ivltests/sv_darray_min_max.v create mode 100644 ivtest/ivltests/sv_darray_min_max_with.v create mode 100644 ivtest/ivltests/sv_darray_unique.v create mode 100644 ivtest/ivltests/sv_darray_unique_with.v create mode 100644 ivtest/ivltests/sv_queue_min_max.v create mode 100644 ivtest/ivltests/sv_queue_min_max_with.v create mode 100644 ivtest/ivltests/sv_queue_unique_with.v create mode 100644 ivtest/vvp_tests/sv_class_darray_prop_locators.json create mode 100644 ivtest/vvp_tests/sv_darray_min_max.json create mode 100644 ivtest/vvp_tests/sv_darray_min_max_with.json create mode 100644 ivtest/vvp_tests/sv_darray_unique.json create mode 100644 ivtest/vvp_tests/sv_darray_unique_with.json create mode 100644 ivtest/vvp_tests/sv_queue_min_max.json create mode 100644 ivtest/vvp_tests/sv_queue_min_max_with.json create mode 100644 ivtest/vvp_tests/sv_queue_unique_with.json diff --git a/elab_expr.cc b/elab_expr.cc index 74cdfe8c9..bb187f19d 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -122,6 +122,14 @@ static NetExpr* elab_queue_locator_with_predicate( sfunc_name = lex_strings.make("$ivl_queue_method$find_last_with"); } else if (method_suffix == "find_last_index") { sfunc_name = lex_strings.make("$ivl_queue_method$find_last_index_with"); + } else if (method_suffix == "unique") { + sfunc_name = lex_strings.make("$ivl_queue_method$unique_with"); + } else if (method_suffix == "unique_index") { + sfunc_name = lex_strings.make("$ivl_queue_method$unique_index_with"); + } else if (method_suffix == "min") { + 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 { ivl_assert(loc, 0); } @@ -140,7 +148,8 @@ static bool is_array_locator_method(perm_string name) return name == "find" || name == "find_index" || name == "find_first" || name == "find_first_index" || name == "find_last" || name == "find_last_index" || - name == "unique" || name == "unique_index"; + name == "unique" || name == "unique_index" || + name == "min" || name == "max"; } static bool locator_returns_indices(perm_string name) @@ -178,17 +187,8 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope, char sfunc[64]; snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s", method_name.str()); - if (method_name == "unique" || method_name == "unique_index") { - 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, result_type, 1); - sys_expr->set_line(loc); - sys_expr->parm(0, array_arg); - return sys_expr; - } + bool no_arg = method_name == "unique" || method_name == "unique_index" || + method_name == "min" || method_name == "max"; if (with_expr) { if (!parms.empty()) { @@ -203,6 +203,18 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope, result_type, method_name); } + if (no_arg) { + 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, result_type, 1); + sys_expr->set_line(loc); + sys_expr->parm(0, array_arg); + return sys_expr; + } + NetExpr* cmp = elab_queue_locator_cmp_arg(des, scope, loc, parms, element_type); if (!cmp) return 0; @@ -1818,7 +1830,9 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*, return expr_width_; } - if (method_name == "find" || method_name == "find_index") { + if (method_name == "find" || method_name == "find_index" || + method_name == "unique" || method_name == "unique_index" || + method_name == "min" || method_name == "max") { expr_type_ = IVL_VT_QUEUE; expr_width_ = 1; min_width_ = 1; @@ -1873,15 +1887,9 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*, return expr_width_; } - if (method_name == "unique" || method_name == "unique_index") { - expr_type_ = IVL_VT_QUEUE; - expr_width_ = 1; - min_width_ = 1; - signed_flag_ = false; - return expr_width_; - } - - if (method_name == "find" || method_name == "find_index") { + if (method_name == "unique" || method_name == "unique_index" || + method_name == "min" || method_name == "max" || + method_name == "find" || method_name == "find_index") { expr_type_ = IVL_VT_QUEUE; expr_width_ = 1; min_width_ = 1; @@ -3835,6 +3843,7 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, NetEProperty*prop = new NetEProperty(search_results.net, pidx, nullptr); prop->set_line(*this); perm_string method_name = search_results.path_tail.back().name; + ivl_type_t element_type = ivl_type_element(ptype); if (method_name == "size") { if (parms_.size() != 0) { cerr << get_fileline() << ": error: size() method " @@ -3846,6 +3855,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, sys_expr->parm(0, prop); return sys_expr; } + if (is_array_locator_method(method_name)) { + return elab_array_locator_method(des, scope, *this, + method_name, prop, element_type, + ptype, parms_, with_expr_, + "dynamic array"); + } } } } @@ -5237,6 +5252,23 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, 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 + << "() for this element type is not yet supported." << endl; + des->errors += 1; + return 0; + } + NetESFunc*fun = new NetESFunc( + member_comp.name == "min" ? "$ivl_queue_method$min" + : "$ivl_queue_method$max", + static_cast(queue), 1); + fun->set_line(*this); + NetESignal*arg = new NetESignal(sr.net); + arg->set_line(*sr.net); + fun->parm(0, arg); + return fun; + } cerr << get_fileline() << ": error: Unknown or unsupported queue " << "member `" << member_comp.name << "'." << endl; des->errors += 1; @@ -5554,6 +5586,23 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, 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 + << "() for this element type is not yet supported." << endl; + des->errors += 1; + return 0; + } + NetESFunc*fun = new NetESFunc( + member_comp.name == "min" ? "$ivl_queue_method$min" + : "$ivl_queue_method$max", + static_cast(queue), 1); + fun->set_line(*this); + NetESignal*arg = new NetESignal(sr.net); + arg->set_line(*sr.net); + fun->parm(0, arg); + return fun; + } } // Dynamic array (not queue) — array location / reduction methods. diff --git a/ivtest/ivltests/sv_class_darray_prop_locators.v b/ivtest/ivltests/sv_class_darray_prop_locators.v new file mode 100644 index 000000000..5f7da3ec7 --- /dev/null +++ b/ivtest/ivltests/sv_class_darray_prop_locators.v @@ -0,0 +1,63 @@ +// Regression: class dynamic-array 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 d[]; + endclass + + C c; + int r[$]; + + initial begin + c = new; + c.d = '{4, 7, 2, 5, 7, 1, 6, 3, 1}; + + r = c.d.find() with (item > 3); + `check(r.size, 5); + `check(r[0], 4); + `check(r[4], 6); + + r = c.d.find_first() with (item > 6); + `check(r.size, 1); + `check(r[0], 7); + + r = c.d.find_last_index() with (item < 3); + `check(r.size, 1); + `check(r[0], 8); + + r = c.d.unique(); + `check(r.size, 7); + `check(r[0], 4); + + r = c.d.unique_index(); + `check(r.size, 7); + `check(r[0], 0); + + r = c.d.unique() with (item > 2); + `check(r.size, 5); + `check(r[0], 4); + `check(r[4], 3); + + r = c.d.unique_index() with (item > 2); + `check(r.size, 6); + `check(r[0], 0); + `check(r[5], 7); + + r = c.d.min(); + `check(r.size, 2); + `check(r[0], 1); + `check(r[1], 1); + + r = c.d.max() with (item < 7); + `check(r.size, 1); + `check(r[0], 6); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_darray_min_max.v b/ivtest/ivltests/sv_darray_min_max.v new file mode 100644 index 000000000..58265c560 --- /dev/null +++ b/ivtest/ivltests/sv_darray_min_max.v @@ -0,0 +1,36 @@ +// Regression: dynamic array min() and max() locator methods return queues. + +module top; + + bit failed = 0; + + `define CHK(cond) \ + if (!(cond)) begin \ + $display("FAILED line %0d", `__LINE__); \ + failed = 1; \ + end + + int a[] = '{4, 7, 2, 5, 7, 1, 6, 3, 1}; + int empty[]; + int r[$]; + + initial begin + r = a.min(); + `CHK(r.size == 2); + `CHK(r[0] == 1); + `CHK(r[1] == 1); + + r = a.max(); + `CHK(r.size == 2); + `CHK(r[0] == 7); + `CHK(r[1] == 7); + + r = empty.min(); + `CHK(r.size == 0); + r = empty.max(); + `CHK(r.size == 0); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_darray_min_max_with.v b/ivtest/ivltests/sv_darray_min_max_with.v new file mode 100644 index 000000000..834822932 --- /dev/null +++ b/ivtest/ivltests/sv_darray_min_max_with.v @@ -0,0 +1,30 @@ +// Regression: dynamic array min/max with(predicate) locator methods. + +module top; + + bit failed = 0; + + `define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end + + int a[] = '{4, 7, 2, 5, 7, 1, 6, 3, 1}; + int r[$]; + + initial begin + r = a.min() with (item > 3); + `CHK(r.size == 1); + `CHK(r[0] == 4); + + r = a.max() with (item < 7); + `CHK(r.size == 1); + `CHK(r[0] == 6); + + r = a.min() with (item > 99); + `CHK(r.size == 0); + + r = a.max() with (item > 99); + `CHK(r.size == 0); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_darray_unique.v b/ivtest/ivltests/sv_darray_unique.v new file mode 100644 index 000000000..ee0b00ef7 --- /dev/null +++ b/ivtest/ivltests/sv_darray_unique.v @@ -0,0 +1,29 @@ +// Regression: dynamic array unique() and unique_index(). + +module top; + + bit failed = 0; + + `define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end + + int a[] = '{1, 2, 1, 3, 2}; + int u[$]; + int ix[$]; + + initial begin + u = a.unique(); + `CHK(u.size == 3); + `CHK(u[0] == 1); + `CHK(u[1] == 2); + `CHK(u[2] == 3); + + ix = a.unique_index(); + `CHK(ix.size == 3); + `CHK(ix[0] == 0); + `CHK(ix[1] == 1); + `CHK(ix[2] == 3); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_darray_unique_with.v b/ivtest/ivltests/sv_darray_unique_with.v new file mode 100644 index 000000000..b4fa97518 --- /dev/null +++ b/ivtest/ivltests/sv_darray_unique_with.v @@ -0,0 +1,33 @@ +// Regression: dynamic array unique()/unique_index() with predicate. + +module top; + + bit failed = 0; + + `define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end + + int a[] = '{4, 7, 2, 5, 7, 1, 6, 3, 1}; + int r[$]; + + initial begin + r = a.unique() with (item > 2); + `CHK(r.size == 5); + `CHK(r[0] == 4); + `CHK(r[1] == 7); + `CHK(r[2] == 5); + `CHK(r[3] == 6); + `CHK(r[4] == 3); + + r = a.unique_index() with (item > 2); + `CHK(r.size == 6); + `CHK(r[0] == 0); + `CHK(r[1] == 1); + `CHK(r[2] == 3); + `CHK(r[3] == 4); + `CHK(r[4] == 6); + `CHK(r[5] == 7); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_min_max.v b/ivtest/ivltests/sv_queue_min_max.v new file mode 100644 index 000000000..872bc0d44 --- /dev/null +++ b/ivtest/ivltests/sv_queue_min_max.v @@ -0,0 +1,47 @@ +// Regression: queue min() and max() locator methods return queues. + +module top; + + bit failed = 0; + + `define CHK(cond) \ + if (!(cond)) begin \ + $display("FAILED line %0d", `__LINE__); \ + failed = 1; \ + end + + int q[$]; + int e[$]; + int r[$]; + + initial begin + q.delete(); + q.push_back(4); + q.push_back(7); + q.push_back(2); + q.push_back(5); + q.push_back(7); + q.push_back(1); + q.push_back(6); + q.push_back(3); + q.push_back(1); + + r = q.min(); + `CHK(r.size == 2); + `CHK(r[0] == 1); + `CHK(r[1] == 1); + + r = q.max(); + `CHK(r.size == 2); + `CHK(r[0] == 7); + `CHK(r[1] == 7); + + r = e.min(); + `CHK(r.size == 0); + r = e.max(); + `CHK(r.size == 0); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_min_max_with.v b/ivtest/ivltests/sv_queue_min_max_with.v new file mode 100644 index 000000000..86607af8b --- /dev/null +++ b/ivtest/ivltests/sv_queue_min_max_with.v @@ -0,0 +1,41 @@ +// Regression: queue min/max with(predicate) locator methods. + +module top; + + bit failed = 0; + + `define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end + + int q[$]; + int r[$]; + + initial begin + q.delete(); + q.push_back(4); + q.push_back(7); + q.push_back(2); + q.push_back(5); + q.push_back(7); + q.push_back(1); + q.push_back(6); + q.push_back(3); + q.push_back(1); + + r = q.min() with (item > 3); + `CHK(r.size == 1); + `CHK(r[0] == 4); + + r = q.max() with (item < 7); + `CHK(r.size == 1); + `CHK(r[0] == 6); + + r = q.min() with (item > 99); + `CHK(r.size == 0); + + r = q.max() with (item > 99); + `CHK(r.size == 0); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_unique_with.v b/ivtest/ivltests/sv_queue_unique_with.v new file mode 100644 index 000000000..1957a8365 --- /dev/null +++ b/ivtest/ivltests/sv_queue_unique_with.v @@ -0,0 +1,35 @@ +// Regression: queue unique()/unique_index() with predicate. + +module top; + + bit failed = 0; + + `define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end + + int q[$]; + int r[$]; + + initial begin + q = '{4, 7, 2, 5, 7, 1, 6, 3, 1}; + + r = q.unique() with (item > 2); + `CHK(r.size == 5); + `CHK(r[0] == 4); + `CHK(r[1] == 7); + `CHK(r[2] == 5); + `CHK(r[3] == 6); + `CHK(r[4] == 3); + + r = q.unique_index() with (item > 2); + `CHK(r.size == 6); + `CHK(r[0] == 0); + `CHK(r[1] == 1); + `CHK(r[2] == 3); + `CHK(r[3] == 4); + `CHK(r[4] == 6); + `CHK(r[5] == 7); + + if (!failed) + $display("PASSED"); + end +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 29d877666..38a643dc0 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -283,6 +283,7 @@ sv_class_prop_assign_op1 vvp_tests/sv_class_prop_assign_op1.json sv_class_prop_assign_op2 vvp_tests/sv_class_prop_assign_op2.json sv_class_prop_class_name vvp_tests/sv_class_prop_class_name.json sv_class_prop_logic vvp_tests/sv_class_prop_logic.json +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 @@ -309,6 +310,10 @@ 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_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_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 sv_default_port_value1 vvp_tests/sv_default_port_value1.json sv_default_port_value2 vvp_tests/sv_default_port_value2.json @@ -401,7 +406,10 @@ sv_queue_method_push_back_too_few_arg_fail vvp_tests/sv_queue_method_push_back_t sv_queue_method_push_back_too_many_arg_fail vvp_tests/sv_queue_method_push_back_too_many_arg_fail.json sv_queue_method_push_front_too_few_arg_fail vvp_tests/sv_queue_method_push_front_too_few_arg_fail.json 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_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 sv_soft_packed_union_fail1 vvp_tests/sv_soft_packed_union_fail1.json sv_string_method_substr_too_few_arg_fail vvp_tests/sv_string_method_substr_too_few_arg_fail.json diff --git a/ivtest/vvp_tests/sv_class_darray_prop_locators.json b/ivtest/vvp_tests/sv_class_darray_prop_locators.json new file mode 100644 index 000000000..2cd98f13c --- /dev/null +++ b/ivtest/vvp_tests/sv_class_darray_prop_locators.json @@ -0,0 +1,10 @@ +{ + "type" : "normal", + "source" : "sv_class_darray_prop_locators.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Classes/dynamic arrays are not supported", + "type" : "CE", + "iverilog-args" : [ "-pallowsigned=1" ] + } +} diff --git a/ivtest/vvp_tests/sv_darray_min_max.json b/ivtest/vvp_tests/sv_darray_min_max.json new file mode 100644 index 000000000..d184b70b4 --- /dev/null +++ b/ivtest/vvp_tests/sv_darray_min_max.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_darray_min_max.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog dynamic array min/max locator methods", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_darray_min_max_with.json b/ivtest/vvp_tests/sv_darray_min_max_with.json new file mode 100644 index 000000000..e8d3e6c94 --- /dev/null +++ b/ivtest/vvp_tests/sv_darray_min_max_with.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_darray_min_max_with.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog dynamic array min/max with predicate", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_darray_unique.json b/ivtest/vvp_tests/sv_darray_unique.json new file mode 100644 index 000000000..a5e5c5ad8 --- /dev/null +++ b/ivtest/vvp_tests/sv_darray_unique.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_darray_unique.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog dynamic array unique methods", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_darray_unique_with.json b/ivtest/vvp_tests/sv_darray_unique_with.json new file mode 100644 index 000000000..251b10a43 --- /dev/null +++ b/ivtest/vvp_tests/sv_darray_unique_with.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_darray_unique_with.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog darray unique with predicate", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_queue_min_max.json b/ivtest/vvp_tests/sv_queue_min_max.json new file mode 100644 index 000000000..623bad2f8 --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_min_max.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_queue_min_max.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog queue min/max locator methods", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_queue_min_max_with.json b/ivtest/vvp_tests/sv_queue_min_max_with.json new file mode 100644 index 000000000..82b176dda --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_min_max_with.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_queue_min_max_with.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog queue min/max with predicate", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_queue_unique_with.json b/ivtest/vvp_tests/sv_queue_unique_with.json new file mode 100644 index 000000000..f353cb83c --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_unique_with.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_queue_unique_with.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "SystemVerilog queue unique with predicate", + "type" : "CE" + } +} diff --git a/tgt-vvp/eval_object.c b/tgt-vvp/eval_object.c index 14da5fd8f..5a93cd4fa 100644 --- a/tgt-vvp/eval_object.c +++ b/tgt-vvp/eval_object.c @@ -173,6 +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) +{ + 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; + + 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); + + 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) { + 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"); + } + break; + case IVL_VT_REAL: + for (unsigned idx = 0; idx < ivl_expr_parms(ex); idx += 1) { + 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"); + fprintf(vvp_out, " %%pop/real 1;\n"); + } + break; + case IVL_VT_STRING: + for (unsigned idx = 0; idx < ivl_expr_parms(ex); idx += 1) { + 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"); + fprintf(vvp_out, " %%pop/str 1;\n"); + } + break; + default: + fprintf(vvp_out, "; ERROR: eval_darray_pattern_object: unsupported " + "element type %d\n", ivl_type_base(element_type)); + errors += 1; + break; + } + + return errors; +} + static int eval_class_new(ivl_expr_t ex) { ivl_type_t class_type = ivl_expr_net_type(ex); @@ -292,7 +345,7 @@ static int emit_queue_locator_opcode(ivl_expr_t arg, unsigned elem_wid, unsigned pidx = ivl_expr_property_idx(arg); fprintf(vvp_out, " %%load/obj v%p_0;\n", cl); fprintf(vvp_out, " %s %u, %u;\n", op_prop_v, pidx, elem_wid); - fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + fprintf(vvp_out, " %%pop/obj 1, 1;\n"); } else { ivl_signal_t sig = ivl_expr_signal(arg); fprintf(vvp_out, " %s v%p_0, %u;\n", op_v, sig, elem_wid); @@ -311,6 +364,10 @@ static int eval_queue_method_unique(ivl_expr_t expr) "%queue/unique/v", "%queue/unique/prop/v" }, { "$ivl_queue_method$unique_index", "%queue/unique/index/v", "%queue/unique/index/prop/v" }, + { "$ivl_queue_method$min", + "%queue/min/v", "%queue/min/prop/v" }, + { "$ivl_queue_method$max", + "%queue/max/v", "%queue/max/prop/v" }, }; const char* name = ivl_expr_name(expr); @@ -338,7 +395,11 @@ enum queue_locator_with_mode_e { QUEUE_WITH_FIND_FIRST, QUEUE_WITH_FIND_FIRST_INDEX, QUEUE_WITH_FIND_LAST, - QUEUE_WITH_FIND_LAST_INDEX + QUEUE_WITH_FIND_LAST_INDEX, + QUEUE_WITH_MIN, + QUEUE_WITH_MAX, + QUEUE_WITH_UNIQUE, + QUEUE_WITH_UNIQUE_INDEX }; static enum queue_locator_with_mode_e queue_locator_with_mode_from_name( @@ -356,6 +417,14 @@ static enum queue_locator_with_mode_e queue_locator_with_mode_from_name( return QUEUE_WITH_FIND_LAST; } else if (strcmp(name, "$ivl_queue_method$find_last_index_with") == 0) { return QUEUE_WITH_FIND_LAST_INDEX; + } else if (strcmp(name, "$ivl_queue_method$min_with") == 0) { + return QUEUE_WITH_MIN; + } else if (strcmp(name, "$ivl_queue_method$max_with") == 0) { + return QUEUE_WITH_MAX; + } else if (strcmp(name, "$ivl_queue_method$unique_with") == 0) { + return QUEUE_WITH_UNIQUE; + } else if (strcmp(name, "$ivl_queue_method$unique_index_with") == 0) { + return QUEUE_WITH_UNIQUE_INDEX; } return (enum queue_locator_with_mode_e) -1; } @@ -368,14 +437,20 @@ static int queue_with_reverse(enum queue_locator_with_mode_e mode) static int queue_with_multi(enum queue_locator_with_mode_e mode) { - return mode == QUEUE_WITH_FIND || mode == QUEUE_WITH_FIND_INDEX; + return mode == QUEUE_WITH_FIND || + mode == QUEUE_WITH_FIND_INDEX || + mode == QUEUE_WITH_MIN || + mode == QUEUE_WITH_MAX || + mode == QUEUE_WITH_UNIQUE || + mode == QUEUE_WITH_UNIQUE_INDEX; } static int queue_with_as_index(enum queue_locator_with_mode_e mode) { return mode == QUEUE_WITH_FIND_INDEX || mode == QUEUE_WITH_FIND_FIRST_INDEX || - mode == QUEUE_WITH_FIND_LAST_INDEX; + mode == QUEUE_WITH_FIND_LAST_INDEX || + mode == QUEUE_WITH_UNIQUE_INDEX; } /* On predicate match: append value/index and continue or stop. */ @@ -435,6 +510,37 @@ static void emit_queue_with_step_index(int reverse, int i_reg, unsigned lab_top) fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top); } +static void emit_queue_with_finish(enum queue_locator_with_mode_e mode, + int is_prop, unsigned elem_wid) +{ + if (mode == QUEUE_WITH_UNIQUE || mode == QUEUE_WITH_UNIQUE_INDEX) { + unsigned wid = (mode == QUEUE_WITH_UNIQUE_INDEX) ? 32 : elem_wid; + fprintf(vvp_out, " %%queue/unique/obj/v %u;\n", wid); + if (is_prop) { + fprintf(vvp_out, " %%pop/obj 1, 1;\n"); + } + return; + } + if (mode == QUEUE_WITH_MIN || mode == QUEUE_WITH_MAX) { + const char* opname = (mode == QUEUE_WITH_MIN) ? "min" : "max"; + fprintf(vvp_out, " %%queue/%s/obj/v %u;\n", opname, elem_wid); + if (is_prop) { + fprintf(vvp_out, " %%pop/obj 1, 1;\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_prop) { + fprintf(vvp_out, " %%pop/obj 1, 1;\n"); + } +} + static int eval_queue_method_find_with(ivl_expr_t expr) { const char* name = ivl_expr_name(expr); @@ -521,19 +627,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); - if (multi) { - fprintf(vvp_out, " %%pop/obj 1, 0;\n"); - } else { - fprintf(vvp_out, " %%queue/new_empty/v;\n"); - fprintf(vvp_out, " %%pop/obj 1, 1;\n"); - } + emit_queue_with_finish(mode, 1, elem_wid); 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); - if (!multi) { - fprintf(vvp_out, " %%queue/new_empty/v;\n"); - } + emit_queue_with_finish(mode, 0, elem_wid); fprintf(vvp_out, "T_%u.%u ; with end (var)\n", thread_count, lab_end); } @@ -622,6 +721,9 @@ int draw_eval_object(ivl_expr_t ex) case IVL_EX_UFUNC: return eval_object_ufunc(ex); + case IVL_EX_ARRAY_PATTERN: + return eval_darray_pattern_object(ex); + case IVL_EX_SFUNC: /* Queue locator `with` may report IVL_VT_DARRAY in ivl; handle by name. */ if (ivl_expr_parms(ex) == 4 && diff --git a/vvp/codes.h b/vvp/codes.h index b0347a092..963648e2c 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -270,6 +270,14 @@ extern bool of_QUEUE_FIND_LAST_INDEX_PROP_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_FIND_LAST_INDEX_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_FIND_LAST_PROP_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_FIND_LAST_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_MIN_PROP_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_MIN_OBJ_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_MIN_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_MAX_PROP_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_MAX_OBJ_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_MAX_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_UNIQUE_OBJ_V(vthread_t thr, vvp_code_t code); +extern bool of_QUEUE_UNIQUE_INDEX_OBJ_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_UNIQUE_INDEX_PROP_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_UNIQUE_INDEX_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_UNIQUE_PROP_V(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 21f5e3efc..9a3b11809 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. */ @@ -292,10 +292,18 @@ static const struct opcode_table_s opcode_table[] = { { "%queue/find_last/index/v", of_QUEUE_FIND_LAST_INDEX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, { "%queue/find_last/prop/v", of_QUEUE_FIND_LAST_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, { "%queue/find_last/v", of_QUEUE_FIND_LAST_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%queue/max/obj/v", of_QUEUE_MAX_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} }, + { "%queue/max/prop/v", of_QUEUE_MAX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%queue/max/v", of_QUEUE_MAX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%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/v", of_QUEUE_NEW_EMPTY_V, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%queue/size/v", of_QUEUE_SIZE_V, 1, {OA_FUNC_PTR, OA_NONE, 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} }, + { "%queue/unique/obj/v", of_QUEUE_UNIQUE_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} }, { "%queue/unique/prop/v", of_QUEUE_UNIQUE_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, { "%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} }, diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 34b23459a..a9cbe91c7 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -540,6 +540,24 @@ static void get_queue_or_darray_vec4_from_net(vthread_t thr, vvp_net_t* net, dsrc = 0; } +static void get_queue_or_darray_vec4_from_object(vvp_object_t src_obj, + vvp_queue_vec4*& qsrc, + vvp_darray*& dsrc) +{ + qsrc = src_obj.peek(); + if (qsrc) { + dsrc = 0; + return; + } + vvp_darray* dany = src_obj.peek(); + if (dany && dynamic_cast(dany) == 0) { + dsrc = dany; + return; + } + qsrc = 0; + dsrc = 0; +} + /* * The following are used to allow a common template to be written for * queue real/string/vec4 operations @@ -6275,6 +6293,41 @@ static vvp_queue_vec4* queue_find_first_last_to_queue_src(SRC* src, return dst; } +/* min()/max() return all elements equal to the selected extrema. */ +template +static vvp_queue_vec4* queue_run_min_max_src(SRC* src, unsigned wid, bool want_max) +{ + vvp_queue_vec4* dst = new vvp_queue_vec4(); + if (!src || src->get_size() == 0) + return dst; + + vvp_vector4_t best(wid); + src->get_word(0, best); + dst->push_back(best, 0); + + size_t n = src->get_size(); + for (size_t i = 1; i < n; i += 1) { + vvp_vector4_t vi(wid); + src->get_word(i, vi); + if (vi.eeq(best)) { + dst->push_back(vi, 0); + continue; + } + + vvp_bit4_t ge = compare_gtge(vi, best, BIT4_1); + bool replace = want_max ? (ge == BIT4_1) : (ge == BIT4_0); + if (!replace) + continue; + + best = vi; + delete dst; + dst = new vvp_queue_vec4(); + dst->push_back(best, 0); + } + + return dst; +} + bool of_QUEUE_FIND_V(vthread_t thr, vvp_code_t cp) { vvp_vector4_t cmp = thr->pop_vec4(); @@ -6309,12 +6362,11 @@ bool of_QUEUE_FIND_PROP_V(vthread_t thr, vvp_code_t cp) vvp_object_t qobj; cobj->get_object(pid, qobj, 0); - vvp_queue_vec4* src = qobj.peek(); - if (src == 0) { - thr->push_object(vvp_object_t(new vvp_queue_vec4())); - return true; - } - vvp_queue_vec4* dst = queue_run_find_matches_src(src, wid, cmp, false); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); + vvp_queue_vec4* dst = qsrc ? queue_run_find_matches_src(qsrc, wid, cmp, false) + : queue_run_find_matches_src(dsrc, wid, cmp, false); thr->push_object(vvp_object_t(dst)); return true; } @@ -6353,12 +6405,11 @@ bool of_QUEUE_FIND_INDEX_PROP_V(vthread_t thr, vvp_code_t cp) vvp_object_t qobj; cobj->get_object(pid, qobj, 0); - vvp_queue_vec4* src = qobj.peek(); - if (src == 0) { - thr->push_object(vvp_object_t(new vvp_queue_vec4())); - return true; - } - vvp_queue_vec4* dst = queue_run_find_matches_src(src, wid, cmp, true); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); + vvp_queue_vec4* dst = qsrc ? queue_run_find_matches_src(qsrc, wid, cmp, true) + : queue_run_find_matches_src(dsrc, wid, cmp, true); thr->push_object(vvp_object_t(dst)); return true; } @@ -6397,9 +6448,12 @@ bool of_QUEUE_FIND_FIRST_PROP_V(vthread_t thr, vvp_code_t cp) vvp_object_t qobj; cobj->get_object(pid, qobj, 0); - vvp_queue_vec4* src = qobj.peek(); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); vvp_queue_vec4* dst = - queue_find_first_last_to_queue_src(src, wid, cmp, true, false); + qsrc ? queue_find_first_last_to_queue_src(qsrc, wid, cmp, true, false) + : queue_find_first_last_to_queue_src(dsrc, wid, cmp, true, false); thr->push_object(vvp_object_t(dst)); return true; } @@ -6438,9 +6492,12 @@ bool of_QUEUE_FIND_FIRST_INDEX_PROP_V(vthread_t thr, vvp_code_t cp) vvp_object_t qobj; cobj->get_object(pid, qobj, 0); - vvp_queue_vec4* src = qobj.peek(); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); vvp_queue_vec4* dst = - queue_find_first_last_to_queue_src(src, wid, cmp, true, true); + qsrc ? queue_find_first_last_to_queue_src(qsrc, wid, cmp, true, true) + : queue_find_first_last_to_queue_src(dsrc, wid, cmp, true, true); thr->push_object(vvp_object_t(dst)); return true; } @@ -6479,9 +6536,12 @@ bool of_QUEUE_FIND_LAST_PROP_V(vthread_t thr, vvp_code_t cp) vvp_object_t qobj; cobj->get_object(pid, qobj, 0); - vvp_queue_vec4* src = qobj.peek(); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); vvp_queue_vec4* dst = - queue_find_first_last_to_queue_src(src, wid, cmp, false, false); + qsrc ? queue_find_first_last_to_queue_src(qsrc, wid, cmp, false, false) + : queue_find_first_last_to_queue_src(dsrc, wid, cmp, false, false); thr->push_object(vvp_object_t(dst)); return true; } @@ -6520,9 +6580,154 @@ bool of_QUEUE_FIND_LAST_INDEX_PROP_V(vthread_t thr, vvp_code_t cp) vvp_object_t qobj; cobj->get_object(pid, qobj, 0); - vvp_queue_vec4* src = qobj.peek(); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); vvp_queue_vec4* dst = - queue_find_first_last_to_queue_src(src, wid, cmp, false, true); + qsrc ? queue_find_first_last_to_queue_src(qsrc, wid, cmp, false, true) + : queue_find_first_last_to_queue_src(dsrc, wid, cmp, false, true); + thr->push_object(vvp_object_t(dst)); + return true; +} + +bool of_QUEUE_MIN_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_queue_vec4* dst; + if (qsrc) + dst = queue_run_min_max_src(qsrc, wid, false); + else if (dsrc) + dst = queue_run_min_max_src(dsrc, wid, false); + else { + vvp_queue* src_q = get_queue_object(thr, net); + vvp_queue_vec4* src = dynamic_cast(src_q); + dst = queue_run_min_max_src(src, wid, false); + } + thr->push_object(vvp_object_t(dst)); + return true; +} + +bool of_QUEUE_MIN_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_queue_vec4* dst = qsrc ? queue_run_min_max_src(qsrc, wid, false) + : queue_run_min_max_src(dsrc, wid, false); + thr->push_object(vvp_object_t(dst)); + return true; +} + +bool of_QUEUE_MIN_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_queue_vec4* dst = qsrc ? queue_run_min_max_src(qsrc, wid, false) + : queue_run_min_max_src(dsrc, wid, false); + thr->push_object(vvp_object_t(dst)); + return true; +} + +bool of_QUEUE_MAX_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_queue_vec4* dst; + if (qsrc) + dst = queue_run_min_max_src(qsrc, wid, true); + else if (dsrc) + dst = queue_run_min_max_src(dsrc, wid, true); + else { + vvp_queue* src_q = get_queue_object(thr, net); + vvp_queue_vec4* src = dynamic_cast(src_q); + dst = queue_run_min_max_src(src, wid, true); + } + thr->push_object(vvp_object_t(dst)); + return true; +} + +bool of_QUEUE_MAX_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_queue_vec4* dst = qsrc ? queue_run_min_max_src(qsrc, wid, true) + : queue_run_min_max_src(dsrc, wid, true); + thr->push_object(vvp_object_t(dst)); + return true; +} + +bool of_QUEUE_MAX_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_queue_vec4* dst = qsrc ? queue_run_min_max_src(qsrc, wid, true) + : queue_run_min_max_src(dsrc, wid, true); + thr->push_object(vvp_object_t(dst)); + return true; +} + +bool of_QUEUE_UNIQUE_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_queue_vec4* dst = qsrc ? queue_run_unique_src(qsrc, wid, false) + : queue_run_unique_src(dsrc, wid, false); + thr->push_object(vvp_object_t(dst)); + return true; +} + +bool of_QUEUE_UNIQUE_INDEX_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_queue_vec4* dst = qsrc ? queue_run_unique_src(qsrc, wid, true) + : queue_run_unique_src(dsrc, wid, true); thr->push_object(vvp_object_t(dst)); return true; } @@ -6557,12 +6762,11 @@ bool of_QUEUE_UNIQUE_PROP_V(vthread_t thr, vvp_code_t cp) vvp_object_t qobj; cobj->get_object(pid, qobj, 0); - vvp_queue_vec4* src = qobj.peek(); - if (src == 0) { - thr->push_object(vvp_object_t(new vvp_queue_vec4())); - return true; - } - vvp_queue_vec4* dst = queue_run_unique_src(src, wid, false); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); + vvp_queue_vec4* dst = qsrc ? queue_run_unique_src(qsrc, wid, false) + : queue_run_unique_src(dsrc, wid, false); thr->push_object(vvp_object_t(dst)); return true; } @@ -6597,12 +6801,11 @@ bool of_QUEUE_UNIQUE_INDEX_PROP_V(vthread_t thr, vvp_code_t cp) vvp_object_t qobj; cobj->get_object(pid, qobj, 0); - vvp_queue_vec4* src = qobj.peek(); - if (src == 0) { - thr->push_object(vvp_object_t(new vvp_queue_vec4())); - return true; - } - vvp_queue_vec4* dst = queue_run_unique_src(src, wid, true); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); + vvp_queue_vec4* dst = qsrc ? queue_run_unique_src(qsrc, wid, true) + : queue_run_unique_src(dsrc, wid, true); thr->push_object(vvp_object_t(dst)); return true; } @@ -6617,9 +6820,11 @@ bool of_PROP_QUEUE_SIZE(vthread_t thr, vvp_code_t cp) vvp_object_t qobj; cobj->get_object(pid, qobj, 0); - const vvp_queue* queue = qobj.peek(); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); - size_t sz = queue ? queue->get_size() : 0; + size_t sz = qsrc ? qsrc->get_size() : (dsrc ? dsrc->get_size() : 0); vvp_vector4_t val(32, BIT4_0); unsigned long ul = sz; @@ -6716,19 +6921,51 @@ bool of_QUEUE_WORD_PROP_V(vthread_t thr, vvp_code_t cp) return true; } + vvp_object_t saved_top; + bool popped_top = false; vvp_object_t& top = thr->peek_object(); vvp_cobject*cobj = top.peek(); - assert(cobj); + if (cobj == 0) { + // Array-locator with(property) keeps an accumulator queue on top. + // Temporarily pop it to access the class object beneath. + thr->pop_object(saved_top); + popped_top = true; + vvp_object_t& below = thr->peek_object(); + cobj = below.peek(); + } + if (cobj == 0) { + if (popped_top) + thr->push_object(saved_top); + thr->push_vec4(vvp_vector4_t(wid)); + return true; + } vvp_object_t qobj; cobj->get_object(pid, qobj, 0); - vvp_queue_vec4* src = qobj.peek(); + vvp_queue_vec4* qsrc = 0; + vvp_darray* dsrc = 0; + get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc); vvp_vector4_t out(wid); - if (src == 0 || (size_t)adr >= src->get_size()) { + if (qsrc) { + if ((size_t)adr >= qsrc->get_size()) { + thr->push_vec4(out); + return true; + } + qsrc->get_word((unsigned)adr, out); + } else if (dsrc) { + if ((size_t)adr >= dsrc->get_size()) { + thr->push_vec4(out); + return true; + } + dsrc->get_word((unsigned)adr, out); + } else { thr->push_vec4(out); + if (popped_top) + thr->push_object(saved_top); return true; } - src->get_word((unsigned)adr, out); + if (popped_top) + thr->push_object(saved_top); thr->push_vec4(out); return true; }