diff --git a/elab_expr.cc b/elab_expr.cc index 4af726d41..7db2ea69e 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -105,8 +105,13 @@ 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") + 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; @@ -131,6 +136,8 @@ 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 ivl_assert(loc, 0); @@ -3849,10 +3856,16 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, des->errors += 1; } if (with_expr_) { - cerr << get_fileline() << ": sorry: queue sum() with a " - << "`with` clause is not yet supported." << endl; - des->errors += 1; - return 0; + if (!parms_.empty()) { + cerr << 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, *this, with_expr_, prop, + element_type, element_type, method_name); } if (!queue_method_element_is_integral_vec4(element_type)) { cerr << get_fileline() << ": sorry: queue sum() for this " @@ -4382,10 +4395,16 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, des->errors += 1; } if (with_expr_) { - cerr << get_fileline() << ": sorry: array sum() with a " - << "`with` clause is not yet supported." << endl; - des->errors += 1; - return 0; + if (!parms_.empty()) { + cerr << 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, *this, with_expr_, prop, + element_type, element_type, method_name); } if (!queue_method_element_is_integral_vec4(element_type)) { cerr << get_fileline() << ": sorry: array sum() for this " @@ -4782,10 +4801,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, des->errors += 1; } if (with_expr_) { - cerr << get_fileline() << ": sorry: dynamic array sum() with a " - << "`with` clause is not yet supported." << endl; - des->errors += 1; - return 0; + if (!parms_.empty()) { + cerr << 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, *this, with_expr_, sub_expr, element_type, + element_type, method_name); } if (!queue_method_element_is_integral_vec4(element_type)) { cerr << get_fileline() << ": sorry: dynamic array sum() for this " @@ -4953,10 +4977,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, des->errors += 1; } if (with_expr_) { - cerr << get_fileline() << ": sorry: queue sum() with a " - << "`with` clause is not yet supported." << endl; - des->errors += 1; - return 0; + if (!parms_.empty()) { + cerr << 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, *this, with_expr_, sub_expr, element_type, + element_type, method_name); } if (!queue_method_element_is_integral_vec4(element_type)) { cerr << get_fileline() << ": sorry: queue sum() for this " diff --git a/ivtest/ivltests/README_sv_queue_locators.txt b/ivtest/ivltests/README_sv_queue_locators.txt index ad992413b..693463290 100644 --- a/ivtest/ivltests/README_sv_queue_locators.txt +++ b/ivtest/ivltests/README_sv_queue_locators.txt @@ -20,6 +20,10 @@ Behavior notes (LRM-oriented): * min() and max() return queues containing all elements equal to the selected extrema. + * sum() returns the scalar reduction sum of elements (integral vector types); + empty arrays/queues yield 0. `sum() with (expr)` reduces the expression + result for each item. + * For dynamic arrays, runtime support treats storage as vvp_darray (including atom-backed integral arrays), not only vvp_queue_vec4. See vvp/vthread.cc: get_queue_or_darray_vec4_from_net() and the %queue/* opcodes used for @@ -51,3 +55,5 @@ Regression tests (see ivtest/vvp_tests/*.json and regress-vvp.list): sv_class_queue_prop_locators.v locator methods on class queue properties. sv_queue_sum.v integral sum() reduction on queues. sv_darray_sum.v integral sum() reduction on dynamic arrays. + sv_queue_sum_with.v sum() with expression on queues. + sv_darray_sum_with.v sum() with expression on dynamic arrays. 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_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 80a9e9b0d..ed1ab62ad 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -258,6 +258,7 @@ 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_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_default_port_value1 vvp_tests/sv_default_port_value1.json @@ -286,6 +287,7 @@ sv_queue_find_with vvp_tests/sv_queue_find_with.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_sum vvp_tests/sv_queue_sum.json +sv_queue_sum_with vvp_tests/sv_queue_sum_with.json sv_wildcard_import8 vvp_tests/sv_wildcard_import8.json sdf_header vvp_tests/sdf_header.json task_return1 vvp_tests/task_return1.json 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_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 0d121c147..1d2b23ed7 100644 --- a/tgt-vvp/eval_object.c +++ b/tgt-vvp/eval_object.c @@ -467,6 +467,8 @@ static int eval_queue_method_find_with(ivl_expr_t expr) mode = 8; else if (strcmp(name, "$ivl_queue_method$unique_index_with") == 0) mode = 9; + else if (strcmp(name, "$ivl_queue_method$sum_with") == 0) + mode = 10; else return 1; @@ -487,7 +489,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 %u;\n", n_reg); if (mode == 0 || mode == 1 || mode == 6 || mode == 7 || - mode == 8 || mode == 9) { + mode == 8 || mode == 9 || mode == 10) { fprintf(vvp_out, " %%queue/new_empty/v;\n"); } if (!reverse) { @@ -518,10 +520,16 @@ static int eval_queue_method_find_with(ivl_expr_t expr) fprintf(vvp_out, " %%push/ix/vec4 %u, 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); + if (mode == 10) { + 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); + } if (mode == 0) { fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig); @@ -543,6 +551,8 @@ static int eval_queue_method_find_with(ivl_expr_t expr) fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg); fprintf(vvp_out, " %%queue/append_word/v 32;\n"); fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom); + } else if (mode == 10) { + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom); } else if (mode == 2) { fprintf(vvp_out, " %%queue/new_empty/v;\n"); fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig); @@ -584,6 +594,9 @@ static int eval_queue_method_find_with(ivl_expr_t expr) if (mode == 0 || mode == 1) { /* Keep result queue object, drop class object beneath it. */ fprintf(vvp_out, " %%pop/obj 1, 1;\n"); + } else if (mode == 10) { + fprintf(vvp_out, " %%queue/sum/obj/v %u;\n", elem_wid); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (mode == 8 || mode == 9) { fprintf(vvp_out, " %%queue/unique/obj/v %u;\n", mode == 9 ? 32 : elem_wid); @@ -602,7 +615,7 @@ 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 %u;\n", n_reg); if (mode == 0 || mode == 1 || mode == 6 || mode == 7 || - mode == 8 || mode == 9) { + mode == 8 || mode == 9 || mode == 10) { fprintf(vvp_out, " %%queue/new_empty/v;\n"); } if (!reverse) { @@ -633,10 +646,16 @@ static int eval_queue_method_find_with(ivl_expr_t expr) fprintf(vvp_out, " %%push/ix/vec4 %u, 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); + if (mode == 10) { + 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); + } if (mode == 0) { fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig); @@ -658,6 +677,8 @@ static int eval_queue_method_find_with(ivl_expr_t expr) fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg); fprintf(vvp_out, " %%queue/append_word/v 32;\n"); fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom); + } else if (mode == 10) { + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom); } else if (mode == 2) { fprintf(vvp_out, " %%queue/new_empty/v;\n"); fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig); @@ -691,7 +712,9 @@ static int eval_queue_method_find_with(ivl_expr_t expr) fprintf(vvp_out, "T_%u.%u ; loop end (var)\n", thread_count, lab_loop_end); - if (mode == 8 || mode == 9) { + if (mode == 10) { + fprintf(vvp_out, " %%queue/sum/obj/v %u;\n", elem_wid); + } else if (mode == 8 || mode == 9) { fprintf(vvp_out, " %%queue/unique/obj/v %u;\n", mode == 9 ? 32 : elem_wid); } else if (mode == 6 || mode == 7) { diff --git a/vvp/codes.h b/vvp/codes.h index a1c3b0f4b..f0e47ed57 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -252,6 +252,7 @@ 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_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); diff --git a/vvp/compile.cc b/vvp/compile.cc index a6bab1c45..fbd35498d 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -299,6 +299,7 @@ static const struct opcode_table_s opcode_table[] = { { "%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/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} }, diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 1997647b8..05334f7b5 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -6467,6 +6467,22 @@ bool of_QUEUE_SUM_PROP_V(vthread_t thr, vvp_code_t cp) 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();