SV: pass chipsalliance sv-tests section 7.12 array methods

Support no-parens darray locators (qi = s.unique) and string-element
find* with() via string queue new/append opcodes so LRM 7.12/7.12.2
sv-tests assign locator results to queues and sort them.
This commit is contained in:
mjoekhan 2026-07-21 12:21:44 +05:00
parent a4989d023d
commit 95a80901de
8 changed files with 287 additions and 109 deletions

View File

@ -47,6 +47,7 @@
using namespace std;
static netqueue_t ivl_queue_unique_index_ret(&netvector_t::atom2s32, -1);
static netqueue_t ivl_queue_string_ret(&netstring_t::type_string, -1);
static bool queue_method_element_is_integral_vec4(ivl_type_t et)
{
@ -54,6 +55,100 @@ static bool queue_method_element_is_integral_vec4(ivl_type_t et)
return bt == IVL_VT_BOOL || bt == IVL_VT_LOGIC;
}
/* Locator methods: integral vec4 always; string only for find*. */
static bool locator_method_element_supported(ivl_type_t et, perm_string method)
{
if (queue_method_element_is_integral_vec4(et))
return true;
if (ivl_type_base(et) != IVL_VT_STRING)
return false;
return method == "find" || method == "find_index" ||
method == "find_first" || method == "find_first_index" ||
method == "find_last" || method == "find_last_index";
}
/*
* No-parens forms (e.g. qi = s.unique) elaborate as PEIdent. Build the
* same NetESFunc used for s.unique() / queue methods.
*/
static NetExpr* elab_array_locator_noparens(Design* des, const LineInfo& loc,
NetNet* net, perm_string method_name,
const char* kind)
{
const netdarray_t* dar = net->darray_type();
ivl_assert(loc, dar);
ivl_type_t element_type = dar->element_type();
const netqueue_t* queue = net->queue_type();
ivl_type_t value_rtype = queue
? static_cast<ivl_type_t>(queue)
: (ivl_type_base(element_type) == IVL_VT_STRING
? static_cast<ivl_type_t>(&ivl_queue_string_ret)
: static_cast<ivl_type_t>(dar));
if (method_name == "size") {
NetESFunc*fun = new NetESFunc("$size", &netvector_t::atom2s32, 1);
fun->set_line(loc);
NetESignal*arg = new NetESignal(net);
arg->set_line(*net);
fun->parm(0, arg);
return fun;
}
if (method_name == "unique" || method_name == "unique_index" ||
method_name == "min" || method_name == "max" ||
method_name == "sum" || method_name == "product") {
if (method_name == "sum" || method_name == "product") {
if (!queue_method_element_is_integral_vec4(element_type)) {
cerr << loc.get_fileline() << ": sorry: " << kind << " "
<< method_name << "() for this "
<< "element type is not yet supported." << endl;
des->errors += 1;
return 0;
}
} else if (!queue_method_element_is_integral_vec4(element_type)) {
cerr << loc.get_fileline() << ": sorry: " << kind << " "
<< method_name << "() for this "
<< "element type is not yet supported." << endl;
des->errors += 1;
return 0;
}
ivl_type_t result_type;
char sfunc[64];
if (method_name == "unique_index") {
result_type = &ivl_queue_unique_index_ret;
snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$unique_index");
} else if (method_name == "sum" || method_name == "product") {
result_type = element_type;
snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s",
method_name.str());
} else {
result_type = value_rtype;
snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s",
method_name.str());
}
NetESFunc*fun = new NetESFunc(sfunc, result_type, 1);
fun->set_line(loc);
NetESignal*arg = new NetESignal(net);
arg->set_line(*net);
fun->parm(0, arg);
return fun;
}
if (method_name == "find" || method_name == "find_index" ||
method_name == "find_first" || method_name == "find_first_index" ||
method_name == "find_last" || method_name == "find_last_index") {
cerr << loc.get_fileline() << ": error: Array locator method `"
<< method_name << "' must be called with one "
<< "argument, e.g. " << method_name << "(value)."
<< endl;
des->errors += 1;
return 0;
}
return 0;
}
/* One argument: value to match using == (same as find with (item == arg)). */
static NetExpr* elab_queue_locator_cmp_arg(Design* des, NetScope* scope,
const LineInfo& loc,
@ -91,12 +186,19 @@ static NetExpr* elab_queue_locator_with_predicate(
NetScope::BEGIN_END);
ws->set_line(&loc);
unsigned ew = ivl_type_packed_width(element_type);
const netvector_t* item_vec = new netvector_t(ivl_type_base(element_type),
(long)ew - 1, 0,
ivl_type_signed(element_type));
NetNet* item_net = new NetNet(ws, lex_strings.make("item"), NetNet::REG,
item_vec);
NetNet* item_net;
unsigned ew = 0;
if (ivl_type_base(element_type) == IVL_VT_STRING) {
item_net = new NetNet(ws, lex_strings.make("item"), NetNet::REG,
&netstring_t::type_string);
} else {
ew = ivl_type_packed_width(element_type);
const netvector_t* item_vec = new netvector_t(ivl_type_base(element_type),
(long)ew - 1, 0,
ivl_type_signed(element_type));
item_net = new NetNet(ws, lex_strings.make("item"), NetNet::REG,
item_vec);
}
item_net->set_line(loc);
item_net->local_flag(true);
@ -182,7 +284,7 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope,
const vector<named_pexpr_t>& parms,
PExpr* with_expr, const char* kind)
{
if (!queue_method_element_is_integral_vec4(element_type)) {
if (!locator_method_element_supported(element_type, method_name)) {
cerr << loc.get_fileline() << ": sorry: " << kind << " "
<< method_name << "() for this "
<< "element type is not yet supported." << endl;
@ -190,9 +292,16 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope,
return 0;
}
ivl_type_t use_value_type = value_queue_type;
if (!locator_returns_indices(method_name) &&
ivl_type_base(element_type) == IVL_VT_STRING &&
ivl_type_base(value_queue_type) == IVL_VT_DARRAY) {
use_value_type = &ivl_queue_string_ret;
}
ivl_type_t result_type = locator_returns_indices(method_name)
? static_cast<ivl_type_t>(&ivl_queue_unique_index_ret)
: value_queue_type;
: use_value_type;
char sfunc[64];
snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s", method_name.str());
@ -5284,6 +5393,21 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
// Dynamic array methods without parentheses (e.g. qi = s.unique).
// Must run before the typed assign fallthrough that treats path_tail
// as a field and compares the array to the context queue type.
if (sr.net->darray_type() && !sr.net->queue_type() &&
(path_.size() > 1 || !sr.path_tail.empty())) {
const name_component_t member_comp = !sr.path_tail.empty()
? sr.path_tail.front()
: path_.back();
NetExpr*tmp = elab_array_locator_noparens(des, *this, sr.net,
member_comp.name,
"dynamic array");
if (tmp) return tmp;
if (des->errors) return 0;
}
ivl_type_t check_type = ntype;
if (const netdarray_t*array_type = dynamic_cast<const netdarray_t*> (ntype)) {
if (array_type->type_compatible(net->net_type()) &&
@ -5632,100 +5756,26 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
// Dynamic array (not queue) — array location / reduction methods.
if (sr.net->darray_type() && !sr.net->queue_type() &&
!sr.path_tail.empty()) {
(path_.size() > 1 || !sr.path_tail.empty())) {
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::elaborate_expr: "
"Ident " << sr.path_head
<< " looking for array property " << sr.path_tail
<< " looking for array property "
<< (sr.path_tail.empty() ? path_.back().name
: sr.path_tail.front().name)
<< endl;
}
ivl_assert(*this, sr.path_tail.size() == 1);
const name_component_t member_comp = sr.path_tail.front();
if (member_comp.name == "size") {
NetESFunc*fun = new NetESFunc("$size",
&netvector_t::atom2s32,
1);
fun->set_line(*this);
const name_component_t member_comp = !sr.path_tail.empty()
? sr.path_tail.front()
: path_.back();
NetExpr*tmp = elab_array_locator_noparens(des, *this, sr.net,
member_comp.name,
"dynamic array");
if (tmp) return tmp;
if (des->errors) return 0;
NetESignal*arg = new NetESignal(sr.net);
arg->set_line(*sr.net);
fun->parm(0, arg);
return fun;
} else if (member_comp.name == "find" ||
member_comp.name == "find_index" ||
member_comp.name == "find_first" ||
member_comp.name == "find_first_index" ||
member_comp.name == "find_last" ||
member_comp.name == "find_last_index") {
cerr << get_fileline() << ": error: Array locator method `"
<< member_comp.name << "' must be called with one "
<< "argument, e.g. " << member_comp.name << "(value)."
<< endl;
des->errors += 1;
return 0;
} else if (member_comp.name == "min") {
cerr << get_fileline() << ": sorry: 'min()' "
"array location method is not currently "
"implemented." << endl;
des->errors += 1;
return 0;
} else if (member_comp.name == "max") {
cerr << get_fileline() << ": sorry: 'max()' "
"array location method is not currently "
"implemented." << endl;
des->errors += 1;
return 0;
} else if (member_comp.name == "unique") {
cerr << get_fileline() << ": sorry: 'unique()' "
"array location method is not currently "
"implemented." << endl;
des->errors += 1;
return 0;
} else if (member_comp.name == "unique_index") {
cerr << get_fileline() << ": sorry: 'unique_index()' "
"array location method is not currently "
"implemented." << endl;
des->errors += 1;
return 0;
// FIXME: Check this is a real or integral type.
} else if (member_comp.name == "sum") {
const netdarray_t* dar_sum = sr.net->darray_type();
ivl_assert(*this, dar_sum);
ivl_type_t element_type = dar_sum->element_type();
if (!queue_method_element_is_integral_vec4(element_type)) {
cerr << get_fileline() << ": sorry: dynamic array sum() for this "
<< "element type is not yet supported." << endl;
des->errors += 1;
return 0;
}
NetESFunc*fun = new NetESFunc("$ivl_queue_method$sum",
element_type, 1);
fun->set_line(*this);
NetESignal*arg = new NetESignal(sr.net);
arg->set_line(*sr.net);
fun->parm(0, arg);
return fun;
} else if (member_comp.name == "product") {
const netdarray_t* dar_sum = sr.net->darray_type();
ivl_assert(*this, dar_sum);
ivl_type_t element_type = dar_sum->element_type();
if (!queue_method_element_is_integral_vec4(element_type)) {
cerr << get_fileline() << ": sorry: dynamic array product() for this "
<< "element type is not yet supported." << endl;
des->errors += 1;
return 0;
}
NetESFunc*fun = new NetESFunc("$ivl_queue_method$product",
element_type, 1);
fun->set_line(*this);
NetESignal*arg = new NetESignal(sr.net);
arg->set_line(*sr.net);
fun->parm(0, arg);
return fun;
// FIXME: Check this is only an integral type.
} else if (member_comp.name == "and") {
if (member_comp.name == "and") {
cerr << get_fileline() << ": sorry: 'and()' "
"array reduction method is not currently "
"implemented." << endl;

View File

@ -12,6 +12,9 @@ module top;
int array[] = '{4, 7, 2, 5, 7, 1, 6, 3, 1};
int res[$];
string s[] = '{"hello", "sad", "hello", "world"};
string qs[$];
int qi[$];
initial begin
res = array.find() with (item > 3);
@ -42,6 +45,30 @@ module top;
`CHK(res.size == 1);
`CHK(res[0] == 8);
qs = s.find with (item == "sad");
`CHK(qs.size == 1);
`CHK(qs[0] == "sad");
qs = s.find_first with (item == "hello");
`CHK(qs.size == 1);
`CHK(qs[0] == "hello");
qs = s.find_last with (item == "hello");
`CHK(qs.size == 1);
`CHK(qs[0] == "hello");
qi = s.find_index with (item == "world");
`CHK(qi.size == 1);
`CHK(qi[0] == 3);
qi = s.find_first_index with (item == "hello");
`CHK(qi.size == 1);
`CHK(qi[0] == 0);
qi = s.find_last_index with (item == "hello");
`CHK(qi.size == 1);
`CHK(qi[0] == 2);
if (!failed)
$display("PASSED");
end

View File

@ -25,6 +25,13 @@ module top;
`CHK(r[0] == 7);
`CHK(r[1] == 7);
r = a.min;
`CHK(r.size == 2);
`CHK(r[0] == 1);
r = a.max;
`CHK(r.size == 2);
`CHK(r[0] == 7);
r = empty.min();
`CHK(r.size == 0);
r = empty.max();

View File

@ -23,6 +23,21 @@ module top;
`CHK(ix[1] == 1);
`CHK(ix[2] == 3);
// No-parentheses forms (sv-tests style), including assign to queue then sort.
u = a.unique;
u.sort;
`CHK(u.size == 3);
`CHK(u[0] == 1);
`CHK(u[1] == 2);
`CHK(u[2] == 3);
ix = a.unique_index;
ix.sort;
`CHK(ix.size == 3);
`CHK(ix[0] == 0);
`CHK(ix[1] == 1);
`CHK(ix[2] == 3);
if (!failed)
$display("PASSED");
end

View File

@ -359,6 +359,25 @@ static unsigned queue_unique_src_elem_wid(ivl_expr_t arg)
return 0;
}
static int queue_src_elem_is_string(ivl_expr_t arg)
{
ivl_type_t src_q = 0;
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(arg);
unsigned pidx = ivl_expr_property_idx(arg);
src_q = ivl_type_prop_type(ivl_signal_net_type(cl), pidx);
} else if (ivl_expr_type(arg) == IVL_EX_SIGNAL) {
src_q = ivl_signal_net_type(ivl_expr_signal(arg));
} else {
return 0;
}
if (ivl_type_base(src_q) == IVL_VT_QUEUE ||
ivl_type_base(src_q) == IVL_VT_DARRAY) {
return ivl_type_base(ivl_type_element(src_q)) == IVL_VT_STRING;
}
return 0;
}
/*
* Emit a queue locator opcode. Plain signal uses `op_v`; class property
* uses `op_prop_v`. Returning a queue object leaves it on the object stack.
@ -499,17 +518,24 @@ static int queue_with_as_index(enum queue_locator_with_mode_e mode)
/* On predicate match: append value/index and continue or stop. */
static void emit_queue_with_on_match(enum queue_locator_with_mode_e mode,
ivl_signal_t item_sig, int i_reg,
unsigned elem_wid, unsigned match_lab)
unsigned elem_wid, unsigned match_lab,
int is_string)
{
int multi = queue_with_multi(mode);
int as_index = queue_with_as_index(mode);
if (!multi) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
if (is_string && !as_index)
fprintf(vvp_out, " %%queue/new_empty/str;\n");
else
fprintf(vvp_out, " %%queue/new_empty/v;\n");
}
if (as_index) {
fprintf(vvp_out, " %%push/ix/vec4 %d, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
} else if (is_string) {
fprintf(vvp_out, " %%load/str v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/str;\n");
} else {
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
@ -554,7 +580,8 @@ static void emit_queue_with_step_index(int reverse, int i_reg, unsigned lab_top)
}
static void emit_queue_with_finish(enum queue_locator_with_mode_e mode,
int is_prop, unsigned elem_wid)
int is_prop, unsigned elem_wid,
int is_string)
{
if (mode == QUEUE_WITH_UNIQUE || mode == QUEUE_WITH_UNIQUE_INDEX) {
unsigned wid = (mode == QUEUE_WITH_UNIQUE_INDEX) ? 32 : elem_wid;
@ -592,7 +619,10 @@ static void emit_queue_with_finish(enum queue_locator_with_mode_e mode,
}
return;
}
fprintf(vvp_out, " %%queue/new_empty/v;\n");
if (is_string && !queue_with_as_index(mode))
fprintf(vvp_out, " %%queue/new_empty/str;\n");
else
fprintf(vvp_out, " %%queue/new_empty/v;\n");
if (is_prop) {
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
}
@ -610,13 +640,26 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
ivl_expr_t pred = ivl_expr_parm(expr, 1);
ivl_signal_t item_sig = ivl_expr_signal(ivl_expr_parm(expr, 2));
ivl_signal_t idx_sig = ivl_expr_signal(ivl_expr_parm(expr, 3));
unsigned elem_wid = queue_unique_src_elem_wid(qarg);
if (elem_wid == 0) return 1;
int is_string = queue_src_elem_is_string(qarg);
unsigned elem_wid = is_string ? 0 : queue_unique_src_elem_wid(qarg);
if (!is_string && elem_wid == 0) return 1;
enum queue_locator_with_mode_e mode =
queue_locator_with_mode_from_name(name);
if ((int) mode < 0) return 1;
/* String unique/min/max/sum/product with() not implemented yet. */
if (is_string &&
(mode == QUEUE_WITH_UNIQUE || mode == QUEUE_WITH_UNIQUE_INDEX ||
mode == QUEUE_WITH_MIN || mode == QUEUE_WITH_MAX ||
mode == QUEUE_WITH_SUM || mode == QUEUE_WITH_PRODUCT)) {
return 1;
}
/* Class-property string locators need %load/prop/dar/str (not yet). */
if (is_string && (ivl_expr_type(qarg) == IVL_EX_PROPERTY))
return 1;
int i_reg = allocate_word();
int n_reg = allocate_word();
unsigned lab_top = local_count++;
@ -630,6 +673,10 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
/* First/last stop label: property path needs an extra pop. */
unsigned stop_lab = is_prop ? lab_found : lab_end;
unsigned match_lab = multi ? lab_nom : stop_lab;
int as_index = queue_with_as_index(mode);
const char* new_empty = (is_string && !as_index)
? "%queue/new_empty/str"
: "%queue/new_empty/v";
if (is_prop) {
ivl_signal_t cl = ivl_expr_signal(qarg);
@ -638,7 +685,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 %d;\n", n_reg);
if (multi) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
fprintf(vvp_out, " %s;\n", new_empty);
}
emit_queue_with_init_index(reverse, i_reg, n_reg);
fprintf(vvp_out, "T_%u.%u ; queue with loop\n", thread_count, lab_top);
@ -652,18 +699,27 @@ 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 %d;\n", n_reg);
if (multi) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
fprintf(vvp_out, " %s;\n", new_empty);
}
emit_queue_with_init_index(reverse, i_reg, n_reg);
fprintf(vvp_out, "T_%u.%u ; queue with loop (var)\n", thread_count,
lab_top);
emit_queue_with_loop_test(reverse, i_reg, n_reg, lab_loop_end);
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
fprintf(vvp_out, " %%queue/word/v v%p_0, %u, %d;\n", sig, elem_wid,
i_reg);
if (is_string) {
fprintf(vvp_out, " %%ix/mov 3, %d;\n", i_reg);
fprintf(vvp_out, " %%load/dar/str v%p_0;\n", sig);
} else {
fprintf(vvp_out, " %%queue/word/v v%p_0, %u, %d;\n", sig, elem_wid,
i_reg);
}
}
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", item_sig, elem_wid);
if (is_string) {
fprintf(vvp_out, " %%store/str v%p_0;\n", item_sig);
} else {
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", item_sig, elem_wid);
}
fprintf(vvp_out, " %%push/ix/vec4 %d, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, 32;\n", idx_sig);
@ -675,7 +731,8 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
int pf = draw_eval_condition(pred);
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count, lab_nom, pf);
clr_flag(pf);
emit_queue_with_on_match(mode, item_sig, i_reg, elem_wid, match_lab);
emit_queue_with_on_match(mode, item_sig, i_reg, elem_wid, match_lab,
is_string);
}
fprintf(vvp_out, "T_%u.%u ; nomatch\n", thread_count, lab_nom);
@ -689,12 +746,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);
emit_queue_with_finish(mode, 1, elem_wid);
emit_queue_with_finish(mode, 1, elem_wid, is_string);
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);
emit_queue_with_finish(mode, 0, elem_wid);
emit_queue_with_finish(mode, 0, elem_wid, is_string);
fprintf(vvp_out, "T_%u.%u ; with end (var)\n", thread_count, lab_end);
}

View File

@ -258,7 +258,9 @@ extern bool of_QPOP_PROP_F_REAL(vthread_t thr, vvp_code_t code);
extern bool of_QPOP_PROP_F_STR(vthread_t thr, vvp_code_t code);
extern bool of_QPOP_PROP_F_V(vthread_t thr, vvp_code_t code);
extern bool of_PROP_QUEUE_SIZE(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_APPEND_WORD_STR(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_STR(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_NEW_EMPTY_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_PRODUCT_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_PRODUCT_OBJ_V(vthread_t thr, vvp_code_t code);

View File

@ -279,6 +279,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%qpop/prop/f/r", of_QPOP_PROP_F_REAL, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%qpop/prop/f/str", of_QPOP_PROP_F_STR, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%qpop/prop/f/v", of_QPOP_PROP_F_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/append_word/str", of_QUEUE_APPEND_WORD_STR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%queue/append_word/v", of_QUEUE_APPEND_WORD_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%queue/find/index/prop/v", of_QUEUE_FIND_INDEX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/find/index/v", of_QUEUE_FIND_INDEX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
@ -298,6 +299,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%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/str", of_QUEUE_NEW_EMPTY_STR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%queue/new_empty/v", of_QUEUE_NEW_EMPTY_V, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%queue/product/obj/v", of_QUEUE_PRODUCT_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%queue/product/prop/v", of_QUEUE_PRODUCT_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },

View File

@ -7343,12 +7343,30 @@ bool of_PUSH_IX_VEC4(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_QUEUE_NEW_EMPTY_STR(vthread_t thr, vvp_code_t)
{
thr->push_object(vvp_object_t(new vvp_queue_string()));
return true;
}
bool of_QUEUE_NEW_EMPTY_V(vthread_t thr, vvp_code_t)
{
thr->push_object(vvp_object_t(new vvp_queue_vec4()));
return true;
}
bool of_QUEUE_APPEND_WORD_STR(vthread_t thr, vvp_code_t)
{
string elem = thr->pop_str();
vvp_object_t qobj;
thr->pop_object(qobj);
vvp_queue_string* q = qobj.peek<vvp_queue_string>();
assert(q);
q->push_back(elem, 0);
thr->push_object(qobj);
return true;
}
bool of_QUEUE_APPEND_WORD_V(vthread_t thr, vvp_code_t cp)
{
unsigned wid = cp->bit_idx[0];