diff --git a/Statement.h b/Statement.h index 2edfe86ad..fb5499125 100644 --- a/Statement.h +++ b/Statement.h @@ -243,6 +243,7 @@ class PCallTask : public Statement { const char*sys_task_name) const; NetProc*elaborate_queue_method_(Design*des, NetScope*scope, NetNet*net, + perm_string method_name, const char*sys_task_name) const; bool test_task_calls_ok_(Design*des, NetScope*scope) const; diff --git a/elaborate.cc b/elaborate.cc index 09757adfd..265f02079 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3596,6 +3596,23 @@ NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope, vectorargv (1 + nparms); argv[0] = sig; + if (method_name == "delete") { + // The queue delete method takes an optional element. + if (net->queue_type()) { + if (nparms > 1) { + cerr << get_fileline() << ": error: queue method " + << "delete() takes zero or one argument." << endl; + des->errors += 1; + return 0; + } + } else if (nparms > 0) { + cerr << get_fileline() << ": error: darray method " + << "delete() takes no arguments." << endl; + des->errors += 1; + return 0; + } + } + for (unsigned idx = 0 ; idx < nparms ; idx += 1) { PExpr*ex = parms_[idx]; if (ex != 0) { @@ -3618,13 +3635,19 @@ NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope, */ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope, NetNet*net, + perm_string method_name, const char*sys_task_name) const { NetESignal*sig = new NetESignal(net); sig->set_line(*this); unsigned nparms = parms_.size(); - ivl_assert(*this, nparms == 1); + if ((nparms == 0) || (nparms > 1)) { + cerr << get_fileline() << ": error: method " << method_name + << "() requires a single argument." << endl; + des->errors += 1; + return 0; + } ivl_variable_type_t base_type = net->darray_type()->element_base_type(); int context_width = -1; @@ -3684,17 +3707,16 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, // Is this a delete method for dynamic arrays? if (net->darray_type() && method_name=="delete") { - return elaborate_sys_task_method_(des, scope, net, - method_name, + return elaborate_sys_task_method_(des, scope, net, method_name, "$ivl_darray_method$delete"); } if (net->queue_type()) { if (method_name=="push_back") - return elaborate_queue_method_(des, scope, net, + return elaborate_queue_method_(des, scope, net, method_name, "$ivl_queue_method$push_back"); if (method_name=="push_front") - return elaborate_queue_method_(des, scope, net, + return elaborate_queue_method_(des, scope, net, method_name, "$ivl_queue_method$push_front"); } @@ -4381,8 +4403,10 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope, "included)." << endl; # if 0 unsigned base = nset->at(idx).base; -// FIXME: Is this needed since you can select past the vector? - assert((base + wid) <= vwid); +cerr << get_fileline() << ": base = " << base << endl; +// FIXME: make this work with selects that go before the base. + assert(base < vwid); + if (base + wid > vwid) wid = vwid - base; cerr << get_fileline() << ": base = " << base << ", width = " << wid << ", expr width = " << vwid << endl; nset->at(idx).lnk.dump_link(cerr, 4); diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 6b7ed69da..6ffc12e2d 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1748,14 +1748,22 @@ static int show_delete_method(ivl_statement_t net) show_stmt_file_line(net, "Delete object"); unsigned parm_count = ivl_stmt_parm_count(net); - if (parm_count < 1) + if ((parm_count < 1) || (parm_count > 2)) return 1; ivl_expr_t parm = ivl_stmt_parm(net, 0); assert(ivl_expr_type(parm) == IVL_EX_SIGNAL); ivl_signal_t var = ivl_expr_signal(parm); - fprintf(vvp_out, " %%delete/obj v%p_0;\n", var); + /* If this is a queue then it can have an element to delete. */ + if (parm_count == 2) { + if (ivl_type_base(ivl_signal_net_type(var)) != IVL_VT_QUEUE) + return 1; + 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); + } return 0; } @@ -1778,7 +1786,7 @@ static int show_push_frontback_method(ivl_statement_t net, bool is_front) assert(ivl_expr_type(parm0) == IVL_EX_SIGNAL); ivl_signal_t var = ivl_expr_signal(parm0); ivl_type_t var_type = ivl_signal_net_type(var); - assert(ivl_type_base(var_type)== IVL_VT_QUEUE); + assert(ivl_type_base(var_type) == IVL_VT_QUEUE); int idx = allocate_word(); assert(idx >= 0); diff --git a/vvp/codes.h b/vvp/codes.h index 200c6bfbd..77a746954 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -99,6 +99,7 @@ extern bool of_DEASSIGN_WR(vthread_t thr, vvp_code_t code); extern bool of_DEBUG_THR(vthread_t thr, vvp_code_t code); extern bool of_DELAY(vthread_t thr, vvp_code_t code); extern bool of_DELAYX(vthread_t thr, vvp_code_t code); +extern bool of_DELETE_ELEM(vthread_t thr, vvp_code_t code); extern bool of_DELETE_OBJ(vthread_t thr, vvp_code_t code); extern bool of_DISABLE(vthread_t thr, vvp_code_t code); extern bool of_DISABLE_FORK(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 441aa26fc..2a065b222 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -151,6 +151,7 @@ static const struct opcode_table_s opcode_table[] = { { "%debug/thr", of_DEBUG_THR, 1,{OA_STRING, OA_NONE, OA_NONE} }, { "%delay", of_DELAY, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%delayx", of_DELAYX, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, + { "%delete/elem",of_DELETE_ELEM,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} }, { "%delete/obj",of_DELETE_OBJ,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, { "%disable", of_DISABLE, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} }, { "%disable/fork",of_DISABLE_FORK,0,{OA_NONE,OA_NONE, OA_NONE} }, diff --git a/vvp/vthread.cc b/vvp/vthread.cc index cf657f932..242682fe2 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2416,6 +2416,43 @@ bool of_DELAYX(vthread_t thr, vvp_code_t cp) return false; } +bool of_DELETE_ELEM(vthread_t thr, vvp_code_t cp) +{ + vvp_net_t*net = cp->net; + + int64_t idx_val = thr->words[3].w_int; + if (thr->flags[4] == BIT4_1) { + cerr << "Warning: skipping queue delete() with undefined index." + << endl; + return true; + } + if (idx_val < 0) { + cerr << "Warning: skipping queue delete() with negative index." + << endl; + return true; + } + size_t idx = idx_val; + + vvp_fun_signal_object*obj = dynamic_cast (net->fun); + assert(obj); + + vvp_queue*dqueue = obj->get_object().peek(); + if (dqueue == 0) { + cerr << "Warning: skipping delete(" << idx + << ") on empty queue." << endl; + } else { + size_t size = dqueue->get_size(); + if (idx >= size) { + cerr << "Warning: skipping out of range delete(" << idx + << ") on queue of size " << size << "." << endl; + } else { + dqueue->erase(idx); + } + } + + return true; +} + /* %delete/obj