diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 44731fc61..e4138f8cc 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1728,12 +1728,7 @@ static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope) if ((ivl_stmt_nevent(net) == 1) && (ivl_stmt_events(net, 0) == 0)) { assert(ivl_statement_type(ivl_stmt_sub_stmt(net)) == IVL_ST_NOOP); show_stmt_file_line(net, "Wait fork statement."); - fprintf(vvp_out, " %%wait_fork;\n"); - - fprintf(stderr, "%s:%u: vvp.tgt sorry: wait fork is not currently " - "supported.\n", - ivl_stmt_file(net), ivl_stmt_lineno(net)); - vvp_errors += 1; + fprintf(vvp_out, " %%wait/fork;\n"); return 0; } diff --git a/vvp/codes.h b/vvp/codes.h index 709db5495..3cab77057 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -209,6 +209,7 @@ extern bool of_SUBSTR_V(vthread_t thr, vvp_code_t code); extern bool of_TEST_NUL(vthread_t thr, vvp_code_t code); extern bool of_VPI_CALL(vthread_t thr, vvp_code_t code); extern bool of_WAIT(vthread_t thr, vvp_code_t code); +extern bool of_WAIT_FORK(vthread_t thr, vvp_code_t code); extern bool of_XNOR(vthread_t thr, vvp_code_t code); extern bool of_XNORR(vthread_t thr, vvp_code_t code); extern bool of_XOR(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index c5c6857d0..a19264495 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -255,6 +255,7 @@ static const struct opcode_table_s opcode_table[] = { { "%substr/v",of_SUBSTR_V,3,{OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%test_nul", of_TEST_NUL, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, { "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, + { "%wait/fork",of_WAIT_FORK,0,{OA_NONE, OA_NONE, OA_NONE} }, { "%xnor", of_XNOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%xnor/r", of_XNORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%xor", of_XOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index e6c5bc08f..b7bcc2dc2 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -1159,6 +1159,12 @@ threads that await the functor. When the defined sort of event occurs on the functor, a thread schedule event is created for all the threads in its list and the list is cleared. +* %wait/fork + +This instruction puts the current thread to sleep until all the detached +children have finished executing. The last detached child is responsible +for restarting the parent when it finishes. + * %xnor , , This does a bitwise exclusive nor (~^) of the and vector, diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 4895b5a44..eb02532f8 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -204,6 +204,7 @@ struct vthread_s { /* My parent sets this when it wants me to wake it up. */ unsigned i_am_joining :1; unsigned i_am_detached :1; + unsigned i_am_waiting :1; unsigned i_have_ended :1; unsigned waiting_for_event :1; unsigned is_scheduled :1; @@ -543,6 +544,7 @@ vthread_t vthread_new(vvp_code_t pc, struct __vpiScope*scope) thr->i_am_joining = 0; thr->i_am_detached = 0; + thr->i_am_waiting = 0; thr->is_scheduled = 0; thr->i_have_ended = 0; thr->delay_delete = 0; @@ -2604,11 +2606,22 @@ bool of_END(vthread_t thr, vvp_code_t) } /* If this thread is not fully detached then remove it from the - * parents detached_children set. */ + * parents detached_children set and reap it. */ if (thr->i_am_detached) { - assert(thr->parent); - size_t res = thr->parent->detached_children.erase(thr); + vthread_t tmp = thr->parent; + assert(tmp); + size_t res = tmp->detached_children.erase(thr); assert(res == 1); + /* If the parent is waiting for the detached children to + * finish then the last detached child needs to tell the + * parent to wake up when it is finished. */ + if (tmp->i_am_waiting && tmp->detached_children.empty()) { + tmp->i_am_waiting = 0; + schedule_vthread(tmp, 0, true); + } + /* Fully detach this thread so it will be reaped below. */ + thr->i_am_detached = 0; + thr->parent = 0; } /* If I have no parent, then no one can %join me and there is @@ -5590,6 +5603,30 @@ bool of_WAIT(vthread_t thr, vvp_code_t cp) return false; } +/* + * Implement the %wait/fork (SystemVerilog) instruction by suspending + * the current thread until all the detached children have finished. + */ +bool of_WAIT_FORK(vthread_t thr, vvp_code_t) +{ + /* If a %wait/fork is being executed then the parent thread + * cannot be waiting in a join or already waiting. */ + assert(! thr->i_am_joining); + assert(! thr->i_am_waiting); + + /* There should be no active children when waiting. */ + assert(thr->children.empty()); + + /* If there are no detached children then there is nothing to + * wait for. */ + if (thr->detached_children.empty()) return true; + + /* Flag that this process is waiting for the detached children + * to finish and suspend it. */ + thr->i_am_waiting = 1; + return false; +} + bool of_XNOR(vthread_t thr, vvp_code_t cp) {