diff --git a/elab_expr.cc b/elab_expr.cc index ed7e450a9..2535ccb17 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -123,6 +123,10 @@ 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 == "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); @@ -1737,6 +1741,7 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*, } 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; @@ -4131,6 +4136,56 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, ivl_type_t queue_rtype = queue ? static_cast(queue) : static_cast(dar); + if (method_name == "unique") { + if (parms_.size() != 0) { + cerr << get_fileline() << ": error: unique() method " + << "takes no arguments" << endl; + des->errors += 1; + } + if (!queue_method_element_is_integral_vec4(element_type)) { + cerr << get_fileline() << ": sorry: dynamic array unique() for this " + << "element type is not yet supported." << endl; + des->errors += 1; + return 0; + } + if (with_expr_) { + cerr << get_fileline() << ": sorry: dynamic array unique() with a " + << "`with` clause is not yet supported." << endl; + des->errors += 1; + return 0; + } + NetESFunc*sys_expr = new NetESFunc( + "$ivl_queue_method$unique", queue_rtype, 1); + sys_expr->set_line(*this); + sys_expr->parm(0, sub_expr); + return sys_expr; + } + if (method_name == "unique_index") { + if (parms_.size() != 0) { + cerr << get_fileline() << ": error: unique_index() method " + << "takes no arguments" << endl; + des->errors += 1; + } + if (!queue_method_element_is_integral_vec4(element_type)) { + cerr << get_fileline() << ": sorry: dynamic array unique_index() for this " + << "element type is not yet supported." << endl; + des->errors += 1; + return 0; + } + if (with_expr_) { + cerr << get_fileline() << ": sorry: dynamic array unique_index() with a " + << "`with` clause is not yet supported." << endl; + des->errors += 1; + return 0; + } + NetESFunc*sys_expr = new NetESFunc( + "$ivl_queue_method$unique_index", + static_cast(&ivl_queue_unique_index_ret), 1); + sys_expr->set_line(*this); + sys_expr->parm(0, sub_expr); + return sys_expr; + } + if (method_name == "find") { if (!queue_method_element_is_integral_vec4(element_type)) { cerr << get_fileline() << ": sorry: dynamic array find() for this " @@ -4324,10 +4379,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, return 0; } if (with_expr_) { - cerr << get_fileline() << ": sorry: dynamic array " << method_name - << "() 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, + queue_rtype, method_name); } NetESFunc*sys_expr = new NetESFunc( method_name == "min" ? "$ivl_queue_method$min" @@ -4442,10 +4502,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, return 0; } if (with_expr_) { - cerr << get_fileline() << ": sorry: queue " << method_name - << "() 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, + static_cast(queue), method_name); } NetESFunc*sys_expr = new NetESFunc( method_name == "min" ? "$ivl_queue_method$min" diff --git a/ivtest/ivltests/README_sv_queue_locators.txt b/ivtest/ivltests/README_sv_queue_locators.txt index 310371202..a6233e8b5 100644 --- a/ivtest/ivltests/README_sv_queue_locators.txt +++ b/ivtest/ivltests/README_sv_queue_locators.txt @@ -40,5 +40,8 @@ Regression tests (see ivtest/vvp_tests/*.json and regress-vvp.list): sv_queue_find_locators_ext.v Longer queue, compound predicates. sv_queue_unique.v unique / unique_index. sv_darray_find_locators.v Same locator patterns on int[] dynamic array. + sv_darray_unique.v unique() and unique_index() on int[] dynamic array. sv_queue_min_max.v min() and max() on queue values. sv_darray_min_max.v min() and max() on dynamic array values. + sv_queue_min_max_with.v min()/max() with predicate on queue values. + sv_darray_min_max_with.v min()/max() with predicate on dynamic arrays. 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_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/regress-vvp.list b/ivtest/regress-vvp.list index 7ba00290f..ab43a5dd7 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -254,6 +254,8 @@ 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_default_port_value1 vvp_tests/sv_default_port_value1.json sv_default_port_value2 vvp_tests/sv_default_port_value2.json sv_default_port_value3 vvp_tests/sv_default_port_value3.json @@ -278,6 +280,7 @@ sv_queue_find vvp_tests/sv_queue_find.json sv_queue_find_locators_ext vvp_tests/sv_queue_find_locators_ext.json 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_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_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_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/tgt-vvp/eval_object.c b/tgt-vvp/eval_object.c index 7a542ed4f..dd83b02c8 100644 --- a/tgt-vvp/eval_object.c +++ b/tgt-vvp/eval_object.c @@ -373,6 +373,10 @@ static int eval_queue_method_find_with(ivl_expr_t expr) mode = 4; else if (strcmp(name, "$ivl_queue_method$find_last_index_with") == 0) mode = 5; + else if (strcmp(name, "$ivl_queue_method$min_with") == 0) + mode = 6; + else if (strcmp(name, "$ivl_queue_method$max_with") == 0) + mode = 7; else return 1; @@ -392,7 +396,7 @@ static int eval_queue_method_find_with(ivl_expr_t expr) fprintf(vvp_out, " %%load/obj v%p_0;\n", cl); fprintf(vvp_out, " %%prop/queue/size %u;\n", pidx); fprintf(vvp_out, " %%ix/vec4/s %u;\n", n_reg); - if (mode == 0 || mode == 1) { + if (mode == 0 || mode == 1 || mode == 6 || mode == 7) { fprintf(vvp_out, " %%queue/new_empty/v;\n"); } if (!reverse) { @@ -436,6 +440,10 @@ 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 == 6 || mode == 7) { + fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig); + fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid); + 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); @@ -476,6 +484,10 @@ static int eval_queue_method_find_with(ivl_expr_t expr) lab_loop_end); if (mode == 0 || mode == 1) { fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + } else if (mode == 6 || mode == 7) { + fprintf(vvp_out, " %%queue/%s/obj/v %u;\n", + mode == 6 ? "min" : "max", elem_wid); + fprintf(vvp_out, " %%pop/obj 1, 1;\n"); } else { fprintf(vvp_out, " %%queue/new_empty/v;\n"); fprintf(vvp_out, " %%pop/obj 1, 1;\n"); @@ -485,7 +497,7 @@ static int eval_queue_method_find_with(ivl_expr_t expr) ivl_signal_t sig = ivl_expr_signal(qarg); 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) { + if (mode == 0 || mode == 1 || mode == 6 || mode == 7) { fprintf(vvp_out, " %%queue/new_empty/v;\n"); } if (!reverse) { @@ -529,6 +541,10 @@ 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 == 6 || mode == 7) { + fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig); + fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid); + 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); @@ -562,7 +578,10 @@ 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 >= 2) { + if (mode == 6 || mode == 7) { + fprintf(vvp_out, " %%queue/%s/obj/v %u;\n", + mode == 6 ? "min" : "max", elem_wid); + } else if (mode >= 2) { fprintf(vvp_out, " %%queue/new_empty/v;\n"); } fprintf(vvp_out, "T_%u.%u ; with end (var)\n", thread_count, lab_end); diff --git a/vvp/codes.h b/vvp/codes.h index ed383c939..424d9f81c 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -270,8 +270,10 @@ 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_INDEX_PROP_V(vthread_t thr, vvp_code_t code); extern bool of_QUEUE_UNIQUE_INDEX_V(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index d9171af77..7ba90fdb4 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -291,8 +291,10 @@ 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} }, diff --git a/vvp/vthread.cc b/vvp/vthread.cc index cb4c01672..1e46f8642 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -6677,6 +6677,25 @@ bool of_QUEUE_MIN_V(vthread_t thr, vvp_code_t cp) 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 = src_obj.peek(); + vvp_darray* dsrc = 0; + if (!qsrc) { + vvp_darray* dany = src_obj.peek(); + if (dany && dynamic_cast(dany) == 0) + dsrc = dany; + } + 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; @@ -6722,6 +6741,25 @@ bool of_QUEUE_MAX_V(vthread_t thr, vvp_code_t cp) 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 = src_obj.peek(); + vvp_darray* dsrc = 0; + if (!qsrc) { + vvp_darray* dany = src_obj.peek(); + if (dany && dynamic_cast(dany) == 0) + dsrc = dany; + } + 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;