SV: reverse(), sort(), rsort(), shuffle() for queues/darrays

Add ordering methods for queues and dynamic arrays.  Update ivtest gold
files for always_*_warn, br1005, and br_gh710b LXT per review.

Split from steveicarus/iverilog#1330 (part 06/6).
This commit is contained in:
mjoekhan 2026-07-01 12:45:16 +05:00
parent f0b6d3addc
commit afe849249c
23 changed files with 835 additions and 29 deletions

View File

@ -4385,6 +4385,34 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
&netvector_t::atom2s32,
method_name, "$size");
}
if (method_name == "reverse") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_property_method_(des, scope, net, pidx,
method_name,
"$ivl_darray_method$reverse",
parm_names);
}
if (method_name == "sort") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_property_method_(des, scope, net, pidx,
method_name,
"$ivl_darray_method$sort",
parm_names);
}
if (method_name == "rsort") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_property_method_(des, scope, net, pidx,
method_name,
"$ivl_darray_method$rsort",
parm_names);
}
if (method_name == "shuffle") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_property_method_(des, scope, net, pidx,
method_name,
"$ivl_darray_method$shuffle",
parm_names);
}
} else if (ptype && ptype->base_type() == IVL_VT_DARRAY) {
if (method_name == "delete") {
static const std::vector<perm_string> parm_names = {
@ -4400,6 +4428,34 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
&netvector_t::atom2s32,
method_name, "$size");
}
if (method_name == "reverse") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_property_method_(des, scope, net, pidx,
method_name,
"$ivl_darray_method$reverse",
parm_names);
}
if (method_name == "sort") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_property_method_(des, scope, net, pidx,
method_name,
"$ivl_darray_method$sort",
parm_names);
}
if (method_name == "rsort") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_property_method_(des, scope, net, pidx,
method_name,
"$ivl_darray_method$rsort",
parm_names);
}
if (method_name == "shuffle") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_property_method_(des, scope, net, pidx,
method_name,
"$ivl_darray_method$shuffle",
parm_names);
}
}
}
}
@ -4460,29 +4516,25 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
&netvector_t::atom2s32,
method_name, "$size");
} else if (method_name == "reverse") {
cerr << get_fileline() << ": sorry: 'reverse()' "
"array sorting method is not currently supported."
<< endl;
des->errors += 1;
return 0;
} else if (method_name=="sort") {
cerr << get_fileline() << ": sorry: 'sort()' "
"array sorting method is not currently supported."
<< endl;
des->errors += 1;
return 0;
} else if (method_name=="rsort") {
cerr << get_fileline() << ": sorry: 'rsort()' "
"array sorting method is not currently supported."
<< endl;
des->errors += 1;
return 0;
} else if (method_name=="shuffle") {
cerr << get_fileline() << ": sorry: 'shuffle()' "
"array sorting method is not currently supported."
<< endl;
des->errors += 1;
return 0;
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_darray_method$reverse",
parm_names);
} else if (method_name == "sort") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_darray_method$sort",
parm_names);
} else if (method_name == "rsort") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_darray_method$rsort",
parm_names);
} else if (method_name == "shuffle") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_darray_method$shuffle",
parm_names);
}
}

View File

@ -23,7 +23,7 @@
./ivltests/always_comb_warn.v:32: warning: A for statement step must be a simple binary +/- to be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:32: warning: System task ($display) cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:33: warning: System task ($display) cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:34: warning: Dynamic array delete method cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:34: warning: Dynamic array ordering/delete method cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:35: warning: System task ($display) cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:14: warning: An event (tevt) cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:13: warning: A non-integral variable (trl) cannot be synthesized in an always_comb process.

View File

@ -21,7 +21,7 @@
./ivltests/always_ff_warn.v:33: warning: A for statement step must be a simple binary +/- to be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:33: warning: System task ($display) cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:34: warning: System task ($display) cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:35: warning: Dynamic array delete method cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:35: warning: Dynamic array ordering/delete method cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:36: warning: System task ($display) cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:15: warning: An event (tevt) cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:14: warning: A non-integral variable (trl) cannot be synthesized in an always_ff process.

View File

@ -21,7 +21,7 @@
./ivltests/always_latch_warn.v:32: warning: A for statement step must be a simple binary +/- to be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:32: warning: System task ($display) cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:33: warning: System task ($display) cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:34: warning: Dynamic array delete method cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:34: warning: Dynamic array ordering/delete method cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:35: warning: System task ($display) cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:14: warning: An event (tevt) cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:13: warning: A non-integral variable (trl) cannot be synthesized in an always_latch process.

View File

@ -59,6 +59,20 @@ module test;
c.d = '{2, 3, 4};
`check(c.d.product(), 24);
`check(c.d.sum() with (item + 1), 12);
`check(c.d.product() with (item + 1), 60);
c.d = '{1, 2, 3};
c.d.reverse();
`check(c.d[0], 3);
`check(c.d[1], 2);
`check(c.d[2], 1);
c.d = '{3, 1, 2};
c.d.sort();
`check(c.d[0], 1);
`check(c.d[1], 2);
`check(c.d[2], 3);
if (!failed)
$display("PASSED");

View File

@ -51,6 +51,20 @@ module test;
c.q = '{2, 3, 4};
`check(c.q.product(), 24);
`check(c.q.sum() with (item + 1), 12);
`check(c.q.product() with (item + 1), 60);
c.q = '{1, 2, 3};
c.q.reverse();
`check(c.q[0], 3);
`check(c.q[1], 2);
`check(c.q[2], 1);
c.q = '{3, 1, 2};
c.q.sort();
`check(c.q[0], 1);
`check(c.q[1], 2);
`check(c.q[2], 3);
if (!failed)
$display("PASSED");

View File

@ -0,0 +1,32 @@
// Regression: dynamic array reverse() ordering method.
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int a[];
initial begin
a = '{1, 2, 3, 4};
a.reverse();
`CHK(a[0] === 4 && a[1] === 3 && a[2] === 2 && a[3] === 1);
a = new [1];
a[0] = 42;
a.reverse();
`CHK(a[0] === 42);
a = new [0];
a.reverse();
`CHK(a.size() === 0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,33 @@
// Regression: dynamic array sort(), rsort(), shuffle().
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int a[];
int sum0;
initial begin
a = '{3, 1, 4, 1, 5};
a.sort();
`CHK(a[0] === 1 && a[1] === 1 && a[2] === 3 && a[3] === 4 && a[4] === 5);
a = '{3, 1, 4};
a.rsort();
`CHK(a[0] === 4 && a[1] === 3 && a[2] === 1);
a = '{10, -2, 7};
sum0 = a.sum();
a.shuffle();
`CHK(a.sum() === sum0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,31 @@
// Regression: queue reverse() ordering method.
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int q[$];
initial begin
q = '{1, 2, 3, 4};
q.reverse();
`CHK(q[0] === 4 && q[1] === 3 && q[2] === 2 && q[3] === 1);
q = '{99};
q.reverse();
`CHK(q[0] === 99);
q.delete();
q.reverse();
`CHK(q.size() === 0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,33 @@
// Regression: queue sort(), rsort(), shuffle().
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int q[$];
int sum0;
initial begin
q = '{3, 1, 4, 1, 5};
q.sort();
`CHK(q[0] === 1 && q[1] === 1 && q[2] === 3 && q[3] === 4 && q[4] === 5);
q = '{3, 1, 4};
q.rsort();
`CHK(q[0] === 4 && q[1] === 3 && q[2] === 1);
q = '{10, -2, 7};
sum0 = q.sum();
q.shuffle();
`CHK(q.sum() === sum0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -319,6 +319,8 @@ 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_reverse vvp_tests/sv_darray_reverse.json
sv_darray_sort vvp_tests/sv_darray_sort.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
@ -422,6 +424,8 @@ 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_reverse vvp_tests/sv_queue_reverse.json
sv_queue_sort vvp_tests/sv_queue_sort.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

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_reverse.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array reverse()",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_sort.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array sort/rsort/shuffle",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_reverse.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue reverse()",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_sort.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue sort/rsort/shuffle",
"type" : "CE"
}
}

View File

@ -3461,9 +3461,13 @@ bool NetScope::check_synth(ivl_process_type_t pr_type,
bool NetSTask::check_synth(ivl_process_type_t pr_type,
const NetScope* /* scope */) const
{
if (strcmp(name(), "$ivl_darray_method$delete") == 0) {
if (strcmp(name(), "$ivl_darray_method$delete") == 0 ||
strcmp(name(), "$ivl_darray_method$reverse") == 0 ||
strcmp(name(), "$ivl_darray_method$sort") == 0 ||
strcmp(name(), "$ivl_darray_method$rsort") == 0 ||
strcmp(name(), "$ivl_darray_method$shuffle") == 0) {
cerr << get_fileline() << ": warning: Dynamic array "
"delete method cannot be synthesized "
"ordering/delete method cannot be synthesized "
<< get_process_type_as_string(pr_type) << endl;
} else {
cerr << get_fileline() << ": warning: System task ("

View File

@ -1691,11 +1691,68 @@ static int show_delete_method(ivl_statement_t net)
draw_eval_expr_into_integer(ivl_stmt_parm(net, 1), 3);
fprintf(vvp_out, " %%delete/elem v%p_0;\n", var);
} else {
fprintf(vvp_out, " %%delete/obj v%p_0;\n", var);
fprintf(vvp_out, " %%delete/obj v%p_0;\n", var);
}
return 0;
}
static int show_reverse_method(ivl_statement_t net)
{
show_stmt_file_line(net, "reverse dynamic array or queue");
unsigned parm_count = ivl_stmt_parm_count(net);
if (parm_count != 1) return 1;
ivl_expr_t parm = ivl_stmt_parm(net, 0);
if (ivl_expr_type(parm) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(parm);
unsigned pidx = ivl_expr_property_idx(parm);
ivl_type_t sig_type = ivl_signal_net_type(clas);
ivl_type_t arr_type = ivl_type_prop_type(sig_type, pidx);
ivl_variable_type_t bt = ivl_type_base(arr_type);
if (bt != IVL_VT_QUEUE && bt != IVL_VT_DARRAY) return 1;
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
fprintf(vvp_out, " %%reverse/prop/obj %u;\n", pidx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
return 0;
}
assert(ivl_expr_type(parm) == IVL_EX_SIGNAL);
ivl_signal_t var = ivl_expr_signal(parm);
fprintf(vvp_out, " %%reverse/obj v%p_0;\n", var);
return 0;
}
static int show_array_order_method(ivl_statement_t net, const char*descr,
const char*op_signal, const char*op_prop)
{
show_stmt_file_line(net, descr);
unsigned parm_count = ivl_stmt_parm_count(net);
if (parm_count != 1) return 1;
ivl_expr_t parm = ivl_stmt_parm(net, 0);
if (ivl_expr_type(parm) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(parm);
unsigned pidx = ivl_expr_property_idx(parm);
ivl_type_t sig_type = ivl_signal_net_type(clas);
ivl_type_t arr_type = ivl_type_prop_type(sig_type, pidx);
ivl_variable_type_t bt = ivl_type_base(arr_type);
if (bt != IVL_VT_QUEUE && bt != IVL_VT_DARRAY) return 1;
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
fprintf(vvp_out, " %s %u;\n", op_prop, pidx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
return 0;
}
assert(ivl_expr_type(parm) == IVL_EX_SIGNAL);
ivl_signal_t var = ivl_expr_signal(parm);
fprintf(vvp_out, " %s v%p_0;\n", op_signal, var);
return 0;
}
static int show_insert_method(ivl_statement_t net)
{
show_stmt_file_line(net, "queue: insert");
@ -1881,6 +1938,21 @@ static int show_system_task_call(ivl_statement_t net)
if (strcmp(stmt_name,"$ivl_darray_method$delete") == 0)
return show_delete_method(net);
if (strcmp(stmt_name,"$ivl_darray_method$reverse") == 0)
return show_reverse_method(net);
if (strcmp(stmt_name,"$ivl_darray_method$sort") == 0)
return show_array_order_method(net, "sort dynamic array or queue",
"%sort/obj", "%sort/prop/obj");
if (strcmp(stmt_name,"$ivl_darray_method$rsort") == 0)
return show_array_order_method(net, "rsort dynamic array or queue",
"%rsort/obj", "%rsort/prop/obj");
if (strcmp(stmt_name,"$ivl_darray_method$shuffle") == 0)
return show_array_order_method(net, "shuffle dynamic array or queue",
"%shuffle/obj", "%shuffle/prop/obj");
if (strcmp(stmt_name,"$ivl_queue_method$insert") == 0)
return show_insert_method(net);

View File

@ -214,6 +214,14 @@ extern bool of_REPLICATE(vthread_t thr, vvp_code_t code);
extern bool of_RET_REAL(vthread_t thr, vvp_code_t code);
extern bool of_RET_STR(vthread_t thr, vvp_code_t code);
extern bool of_RET_VEC4(vthread_t thr, vvp_code_t code);
extern bool of_REVERSE_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_REVERSE_PROP_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_RSORT_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_RSORT_PROP_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_SHUFFLE_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_SHUFFLE_PROP_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_SORT_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_SORT_PROP_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_RETLOAD_REAL(vthread_t thr, vvp_code_t code);
extern bool of_RETLOAD_STR(vthread_t thr, vvp_code_t code);
extern bool of_RETLOAD_VEC4(vthread_t thr, vvp_code_t code);

View File

@ -324,6 +324,10 @@ static const struct opcode_table_s opcode_table[] = {
{ "%retload/real",of_RETLOAD_REAL,1,{OA_NUMBER, OA_NONE,OA_NONE} },
{ "%retload/str", of_RETLOAD_STR, 1,{OA_NUMBER, OA_NONE,OA_NONE} },
{ "%retload/vec4",of_RETLOAD_VEC4,1,{OA_NUMBER, OA_NONE,OA_NONE} },
{ "%reverse/obj", of_REVERSE_OBJ, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%reverse/prop/obj", of_REVERSE_PROP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%rsort/obj", of_RSORT_OBJ, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%rsort/prop/obj", of_RSORT_PROP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%scopy", of_SCOPY, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%set/dar/obj/real",of_SET_DAR_OBJ_REAL,1,{OA_NUMBER,OA_NONE,OA_NONE} },
{ "%set/dar/obj/str", of_SET_DAR_OBJ_STR, 1,{OA_NUMBER,OA_NONE,OA_NONE} },
@ -331,6 +335,10 @@ static const struct opcode_table_s opcode_table[] = {
{ "%shiftl", of_SHIFTL, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%shiftr", of_SHIFTR, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%shiftr/s", of_SHIFTR_S, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%shuffle/obj", of_SHUFFLE_OBJ, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%shuffle/prop/obj", of_SHUFFLE_PROP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%sort/obj", of_SORT_OBJ, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%sort/prop/obj", of_SORT_PROP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%split/vec4", of_SPLIT_VEC4, 1,{OA_NUMBER, OA_NONE, OA_NONE} },
{ "%store/dar/r", of_STORE_DAR_R, 1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%store/dar/str", of_STORE_DAR_STR, 1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },

View File

@ -2610,6 +2610,204 @@ bool of_DELETE_OBJ(vthread_t thr, vvp_code_t cp)
return true;
}
/* %reverse/obj <label>
* Reverse element order of the queue or dynamic array object at this net.
*/
bool of_REVERSE_OBJ(vthread_t /*thr*/, vvp_code_t cp)
{
vvp_net_t*net = cp->net;
vvp_fun_signal_object*obj = dynamic_cast<vvp_fun_signal_object*>(net->fun);
assert(obj);
vvp_object_t stor = obj->get_object();
if (stor.test_nil()) return true;
/* Match other queue ops: peek queues before vvp_darray so concrete
queue types dispatch reverse_elems() correctly. */
if (vvp_queue* queue = stor.peek<vvp_queue>()) {
queue->reverse_elems();
return true;
}
vvp_darray*darray = stor.peek<vvp_darray>();
assert(darray);
darray->reverse_elems();
return true;
}
/* %reverse/prop/obj <property-index>
* Reverse queue/darray property storage inside the class object on stack top.
*/
bool of_REVERSE_PROP_OBJ(vthread_t thr, vvp_code_t cp)
{
size_t pid = cp->number;
vvp_object_t& top = thr->peek_object();
vvp_cobject*cobj = top.peek<vvp_cobject>();
assert(cobj);
vvp_object_t arr_obj;
cobj->get_object(pid, arr_obj, 0);
if (arr_obj.test_nil()) return true;
if (vvp_queue* queue = arr_obj.peek<vvp_queue>()) {
queue->reverse_elems();
return true;
}
vvp_darray*darray = arr_obj.peek<vvp_darray>();
assert(darray);
darray->reverse_elems();
return true;
}
/* %sort/obj — ascending sort */
bool of_SORT_OBJ(vthread_t /*thr*/, vvp_code_t cp)
{
vvp_net_t*net = cp->net;
vvp_fun_signal_object*obj = dynamic_cast<vvp_fun_signal_object*>(net->fun);
assert(obj);
vvp_object_t stor = obj->get_object();
if (stor.test_nil()) return true;
if (vvp_queue* queue = stor.peek<vvp_queue>()) {
queue->sort_elems(true);
return true;
}
vvp_darray*darray = stor.peek<vvp_darray>();
assert(darray);
darray->sort_elems(true);
return true;
}
/* %sort/prop/obj */
bool of_SORT_PROP_OBJ(vthread_t thr, vvp_code_t cp)
{
size_t pid = cp->number;
vvp_object_t& top = thr->peek_object();
vvp_cobject*cobj = top.peek<vvp_cobject>();
assert(cobj);
vvp_object_t arr_obj;
cobj->get_object(pid, arr_obj, 0);
if (arr_obj.test_nil()) return true;
if (vvp_queue* queue = arr_obj.peek<vvp_queue>()) {
queue->sort_elems(true);
return true;
}
vvp_darray*darray = arr_obj.peek<vvp_darray>();
assert(darray);
darray->sort_elems(true);
return true;
}
/* %rsort/obj — descending sort */
bool of_RSORT_OBJ(vthread_t /*thr*/, vvp_code_t cp)
{
vvp_net_t*net = cp->net;
vvp_fun_signal_object*obj = dynamic_cast<vvp_fun_signal_object*>(net->fun);
assert(obj);
vvp_object_t stor = obj->get_object();
if (stor.test_nil()) return true;
if (vvp_queue* queue = stor.peek<vvp_queue>()) {
queue->sort_elems(false);
return true;
}
vvp_darray*darray = stor.peek<vvp_darray>();
assert(darray);
darray->sort_elems(false);
return true;
}
/* %rsort/prop/obj */
bool of_RSORT_PROP_OBJ(vthread_t thr, vvp_code_t cp)
{
size_t pid = cp->number;
vvp_object_t& top = thr->peek_object();
vvp_cobject*cobj = top.peek<vvp_cobject>();
assert(cobj);
vvp_object_t arr_obj;
cobj->get_object(pid, arr_obj, 0);
if (arr_obj.test_nil()) return true;
if (vvp_queue* queue = arr_obj.peek<vvp_queue>()) {
queue->sort_elems(false);
return true;
}
vvp_darray*darray = arr_obj.peek<vvp_darray>();
assert(darray);
darray->sort_elems(false);
return true;
}
/* %shuffle/obj */
bool of_SHUFFLE_OBJ(vthread_t /*thr*/, vvp_code_t cp)
{
vvp_net_t*net = cp->net;
vvp_fun_signal_object*obj = dynamic_cast<vvp_fun_signal_object*>(net->fun);
assert(obj);
vvp_object_t stor = obj->get_object();
if (stor.test_nil()) return true;
if (vvp_queue* queue = stor.peek<vvp_queue>()) {
queue->shuffle_elems();
return true;
}
vvp_darray*darray = stor.peek<vvp_darray>();
assert(darray);
darray->shuffle_elems();
return true;
}
/* %shuffle/prop/obj */
bool of_SHUFFLE_PROP_OBJ(vthread_t thr, vvp_code_t cp)
{
size_t pid = cp->number;
vvp_object_t& top = thr->peek_object();
vvp_cobject*cobj = top.peek<vvp_cobject>();
assert(cobj);
vvp_object_t arr_obj;
cobj->get_object(pid, arr_obj, 0);
if (arr_obj.test_nil()) return true;
if (vvp_queue* queue = arr_obj.peek<vvp_queue>()) {
queue->shuffle_elems();
return true;
}
vvp_darray*darray = arr_obj.peek<vvp_darray>();
assert(darray);
darray->shuffle_elems();
return true;
}
/* %delete/tail <label>, idx
*
* Remove all elements after the one specified.

View File

@ -18,15 +18,54 @@
*/
# include "vvp_darray.h"
# include <algorithm>
# include <functional>
# include <iostream>
# include <random>
# include <typeinfo>
using namespace std;
namespace {
static std::mt19937& shuffle_rng(void)
{
static std::mt19937 rng(std::random_device{}());
return rng;
}
static bool vec4_lt_unsigned(const vvp_vector4_t&a, const vvp_vector4_t&b)
{
if (a.eeq(b)) return false;
vvp_bit4_t gt = compare_gtge(b, a, BIT4_1);
if (gt == BIT4_X) return false;
return gt == BIT4_1;
}
} // namespace
vvp_darray::~vvp_darray()
{
}
void vvp_darray::reverse_elems(void)
{
cerr << "XXXX reverse_elems() not implemented for "
<< typeid(*this).name() << endl;
}
void vvp_darray::sort_elems(bool /*ascending*/)
{
cerr << "XXXX sort_elems() not implemented for "
<< typeid(*this).name() << endl;
}
void vvp_darray::shuffle_elems(void)
{
cerr << "XXXX shuffle_elems() not implemented for "
<< typeid(*this).name() << endl;
}
void vvp_darray::set_word(unsigned, const vvp_vector4_t&)
{
cerr << "XXXX set_word(vvp_vector4_t) not implemented for " << typeid(*this).name() << endl;
@ -82,6 +121,24 @@ template <class TYPE> size_t vvp_darray_atom<TYPE>::get_size() const
return array_.size();
}
template <class TYPE> void vvp_darray_atom<TYPE>::reverse_elems(void)
{
size_t n = array_.size();
for (size_t idx = 0 ; idx < n/2 ; idx += 1)
std::swap(array_[idx], array_[n-1-idx]);
}
template <class TYPE> void vvp_darray_atom<TYPE>::sort_elems(bool ascending)
{
if (ascending) std::sort(array_.begin(), array_.end());
else std::sort(array_.begin(), array_.end(), std::greater<TYPE>());
}
template <class TYPE> void vvp_darray_atom<TYPE>::shuffle_elems(void)
{
std::shuffle(array_.begin(), array_.end(), shuffle_rng());
}
template <class TYPE> void vvp_darray_atom<TYPE>::set_word(unsigned adr, const vvp_vector4_t&value)
{
if (adr >= array_.size())
@ -225,6 +282,56 @@ vvp_vector4_t vvp_darray_vec4::get_bitstream(bool as_vec4)
return vec;
}
void vvp_darray_vec4::reverse_elems(void)
{
size_t n = array_.size();
for (size_t idx = 0 ; idx < n/2 ; idx += 1)
std::swap(array_[idx], array_[n-1-idx]);
}
void vvp_darray_vec4::sort_elems(bool ascending)
{
if (ascending) {
std::sort(array_.begin(), array_.end(), vec4_lt_unsigned);
} else {
std::sort(array_.begin(), array_.end(),
[](const vvp_vector4_t&a, const vvp_vector4_t&b) {
if (a.eeq(b))
return false;
return vec4_lt_unsigned(b, a);
});
}
}
void vvp_darray_vec4::shuffle_elems(void)
{
std::shuffle(array_.begin(), array_.end(), shuffle_rng());
}
void vvp_darray_vec2::reverse_elems(void)
{
size_t n = array_.size();
for (size_t idx = 0 ; idx < n/2 ; idx += 1)
std::swap(array_[idx], array_[n-1-idx]);
}
void vvp_darray_vec2::sort_elems(bool ascending)
{
if (ascending) {
std::sort(array_.begin(), array_.end());
} else {
std::sort(array_.begin(), array_.end(),
[](const vvp_vector2_t&a, const vvp_vector2_t&b) {
return b < a;
});
}
}
void vvp_darray_vec2::shuffle_elems(void)
{
std::shuffle(array_.begin(), array_.end(), shuffle_rng());
}
vvp_darray_vec2::~vvp_darray_vec2()
{
}
@ -322,6 +429,33 @@ void vvp_darray_object::shallow_copy(const vvp_object*obj)
array_[idx] = that->array_[idx];
}
void vvp_darray_object::reverse_elems(void)
{
size_t n = array_.size();
for (size_t idx = 0 ; idx < n/2 ; idx += 1)
std::swap(array_[idx], array_[n-1-idx]);
}
void vvp_darray_object::sort_elems(bool ascending)
{
if (ascending) {
std::sort(array_.begin(), array_.end(),
[](const vvp_object_t&a, const vvp_object_t&b) {
return a.sort_order_key() < b.sort_order_key();
});
} else {
std::sort(array_.begin(), array_.end(),
[](const vvp_object_t&a, const vvp_object_t&b) {
return a.sort_order_key() > b.sort_order_key();
});
}
}
void vvp_darray_object::shuffle_elems(void)
{
std::shuffle(array_.begin(), array_.end(), shuffle_rng());
}
vvp_darray_real::~vvp_darray_real()
{
}
@ -358,6 +492,24 @@ void vvp_darray_real::shallow_copy(const vvp_object*obj)
array_[idx] = that->array_[idx];
}
void vvp_darray_real::reverse_elems(void)
{
size_t n = array_.size();
for (size_t idx = 0 ; idx < n/2 ; idx += 1)
std::swap(array_[idx], array_[n-1-idx]);
}
void vvp_darray_real::sort_elems(bool ascending)
{
if (ascending) std::sort(array_.begin(), array_.end());
else std::sort(array_.begin(), array_.end(), std::greater<double>());
}
void vvp_darray_real::shuffle_elems(void)
{
std::shuffle(array_.begin(), array_.end(), shuffle_rng());
}
vvp_object* vvp_darray_real::duplicate(void) const
{
vvp_darray_real*that = new vvp_darray_real(array_.size());
@ -430,6 +582,24 @@ void vvp_darray_string::shallow_copy(const vvp_object*obj)
array_[idx] = that->array_[idx];
}
void vvp_darray_string::reverse_elems(void)
{
size_t n = array_.size();
for (size_t idx = 0 ; idx < n/2 ; idx += 1)
std::swap(array_[idx], array_[n-1-idx]);
}
void vvp_darray_string::sort_elems(bool ascending)
{
if (ascending) std::sort(array_.begin(), array_.end());
else std::sort(array_.begin(), array_.end(), std::greater<string>());
}
void vvp_darray_string::shuffle_elems(void)
{
std::shuffle(array_.begin(), array_.end(), shuffle_rng());
}
vvp_object* vvp_darray_string::duplicate(void) const
{
vvp_darray_string*that = new vvp_darray_string(array_.size());
@ -769,6 +939,38 @@ void vvp_queue_string::erase_tail(unsigned idx)
queue.resize(idx);
}
void vvp_queue_real::reverse_elems(void)
{
std::reverse(queue.begin(), queue.end());
}
void vvp_queue_string::reverse_elems(void)
{
std::reverse(queue.begin(), queue.end());
}
void vvp_queue_real::sort_elems(bool ascending)
{
if (ascending) std::sort(queue.begin(), queue.end());
else std::sort(queue.begin(), queue.end(), std::greater<double>());
}
void vvp_queue_real::shuffle_elems(void)
{
std::shuffle(queue.begin(), queue.end(), shuffle_rng());
}
void vvp_queue_string::sort_elems(bool ascending)
{
if (ascending) std::sort(queue.begin(), queue.end());
else std::sort(queue.begin(), queue.end(), std::greater<string>());
}
void vvp_queue_string::shuffle_elems(void)
{
std::shuffle(queue.begin(), queue.end(), shuffle_rng());
}
void vvp_queue_vec4::copy_elems(vvp_object_t src, unsigned max_size)
{
if (vvp_queue*src_queue = src.peek<vvp_queue>())
@ -876,3 +1078,27 @@ void vvp_queue_vec4::erase_tail(unsigned idx)
if (queue.size() > idx)
queue.resize(idx);
}
void vvp_queue_vec4::reverse_elems(void)
{
std::reverse(queue.begin(), queue.end());
}
void vvp_queue_vec4::sort_elems(bool ascending)
{
if (ascending) {
std::sort(queue.begin(), queue.end(), vec4_lt_unsigned);
} else {
std::sort(queue.begin(), queue.end(),
[](const vvp_vector4_t&a, const vvp_vector4_t&b) {
if (a.eeq(b))
return false;
return vec4_lt_unsigned(b, a);
});
}
}
void vvp_queue_vec4::shuffle_elems(void)
{
std::shuffle(queue.begin(), queue.end(), shuffle_rng());
}

View File

@ -46,6 +46,13 @@ class vvp_darray : public vvp_object {
virtual void get_word(unsigned adr, vvp_object_t&value);
virtual vvp_vector4_t get_bitstream(bool as_vec4);
/* In-place element order reversal (dynamic arrays and queues). */
virtual void reverse_elems(void);
/* sort: ascending if true, descending if false; shuffle randomizes. */
virtual void sort_elems(bool ascending);
virtual void shuffle_elems(void);
};
template <class TYPE> class vvp_darray_atom : public vvp_darray {
@ -55,6 +62,9 @@ template <class TYPE> class vvp_darray_atom : public vvp_darray {
~vvp_darray_atom() override;
size_t get_size(void) const override;
void reverse_elems(void) override;
void sort_elems(bool ascending) override;
void shuffle_elems(void) override;
void set_word(unsigned adr, const vvp_vector4_t&value) override;
void get_word(unsigned adr, vvp_vector4_t&value) override;
void shallow_copy(const vvp_object*obj) override;
@ -78,6 +88,9 @@ class vvp_darray_vec4 : public vvp_darray {
void shallow_copy(const vvp_object*obj) override;
vvp_object* duplicate(void) const override;
vvp_vector4_t get_bitstream(bool as_vec4) override;
void reverse_elems(void) override;
void sort_elems(bool ascending) override;
void shuffle_elems(void) override;
private:
std::vector<vvp_vector4_t> array_;
@ -92,6 +105,9 @@ class vvp_darray_vec2 : public vvp_darray {
~vvp_darray_vec2() override;
size_t get_size(void) const override;
void reverse_elems(void) override;
void sort_elems(bool ascending) override;
void shuffle_elems(void) override;
void set_word(unsigned adr, const vvp_vector4_t&value) override;
void get_word(unsigned adr, vvp_vector4_t&value) override;
void shallow_copy(const vvp_object*obj) override;
@ -114,6 +130,9 @@ class vvp_darray_real : public vvp_darray {
void shallow_copy(const vvp_object*obj) override;
vvp_object* duplicate(void) const override;
vvp_vector4_t get_bitstream(bool as_vec4) override;
void reverse_elems(void) override;
void sort_elems(bool ascending) override;
void shuffle_elems(void) override;
private:
std::vector<double> array_;
@ -130,6 +149,9 @@ class vvp_darray_string : public vvp_darray {
void get_word(unsigned adr, std::string&value) override;
void shallow_copy(const vvp_object*obj) override;
vvp_object* duplicate(void) const override;
void reverse_elems(void) override;
void sort_elems(bool ascending) override;
void shuffle_elems(void) override;
private:
std::vector<std::string> array_;
@ -142,6 +164,9 @@ class vvp_darray_object : public vvp_darray {
~vvp_darray_object() override;
size_t get_size(void) const override;
void reverse_elems(void) override;
void sort_elems(bool ascending) override;
void shuffle_elems(void) override;
void set_word(unsigned adr, const vvp_object_t&value) override;
void get_word(unsigned adr, vvp_object_t&value) override;
void shallow_copy(const vvp_object*obj) override;
@ -196,6 +221,9 @@ class vvp_queue_real : public vvp_queue {
void pop_front(void) override { queue.pop_front(); };
void erase(unsigned idx) override;
void erase_tail(unsigned idx) override;
void reverse_elems(void) override;
void sort_elems(bool ascending) override;
void shuffle_elems(void) override;
private:
std::deque<double> queue;
@ -216,6 +244,9 @@ class vvp_queue_string : public vvp_queue {
void pop_front(void) override { queue.pop_front(); };
void erase(unsigned idx) override;
void erase_tail(unsigned idx) override;
void reverse_elems(void) override;
void sort_elems(bool ascending) override;
void shuffle_elems(void) override;
private:
std::deque<std::string> queue;
@ -236,6 +267,9 @@ class vvp_queue_vec4 : public vvp_queue {
void pop_front(void) override { queue.pop_front(); };
void erase(unsigned idx) override;
void erase_tail(unsigned idx) override;
void reverse_elems(void) override;
void sort_elems(bool ascending) override;
void shuffle_elems(void) override;
private:
std::deque<vvp_vector4_t> queue;

View File

@ -19,6 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include <cstdint>
# include <stdlib.h>
/*
@ -69,6 +70,12 @@ class vvp_object_t {
template <class T> T*peek(void) const;
/* Stable ordering for array-of-handle sort (object identity). */
uintptr_t sort_order_key(void) const
{
return reinterpret_cast<uintptr_t>(ref_);
}
private:
class vvp_object*ref_;
};