vvp: Add `%disable/flow` instruction

The `%disable` instruction will stop the execution of all active
threads of a specific scope. This is what is required to implement
the semantics of the Verilog `disable` statement.

But it is not suited to implement the SystemVerilog flow control
statements such as `return`, `continue` and `break`. These only
affect the thread hierarchy from which it is called, but not other
concurrently running threads from the same scope.

Add a new `%disable/flow` instruction that will only disable the thread
closest to the current thread in the thread hierarchy. This can either be
the thread itself or one of its parents. This will leave other concurrent
threads of the same scope untouched and also allows function recursion
since only the closest parent thread is disabled.

Note that it is not possible to implement this using `%jmp` instructions
since a block in a function with variable declarations will be its own
sub-thread, but using flow control instructions it is possible to exit from
that thread to the parent scope, which is not possible with `%jmp`
instructions.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2022-04-11 17:40:03 +02:00
parent 7c5694e516
commit ca919b3ce0
4 changed files with 37 additions and 0 deletions

View File

@ -103,6 +103,7 @@ 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_DELETE_TAIL(vthread_t thr, vvp_code_t code);
extern bool of_DISABLE(vthread_t thr, vvp_code_t code);
extern bool of_DISABLE_FLOW(vthread_t thr, vvp_code_t code);
extern bool of_DISABLE_FORK(vthread_t thr, vvp_code_t code);
extern bool of_DIV(vthread_t thr, vvp_code_t code);
extern bool of_DIV_S(vthread_t thr, vvp_code_t code);

View File

@ -155,6 +155,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%delete/obj",of_DELETE_OBJ,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%delete/tail",of_DELETE_TAIL,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
{ "%disable", of_DISABLE, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} },
{ "%disable/flow", of_DISABLE_FLOW, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} },
{ "%disable/fork",of_DISABLE_FORK,0,{OA_NONE,OA_NONE, OA_NONE} },
{ "%div", of_DIV, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%div/s", of_DIV_S, 0, {OA_NONE, OA_NONE, OA_NONE} },

View File

@ -469,6 +469,17 @@ This instruction terminates threads that are part of a specific
scope. The label identifies the scope in question, and the threads are
the threads that are currently within that scope.
* %disable/flow <scope-label>
This instruction is similar to `%disable` except that it will only disable a
single thread of the specified scope. The disabled thread will be the thread
closest to the current thread in the thread hierarchy. This can either be thread
itself or one of its parents.
It is used to implement flow control statements called from within a thread that
only affect the thread or its parents. E.g. SystemVerilog `return`, `continue`
or `break`.
* %disable/fork
This instruction terminates all the detached children for the current

View File

@ -2718,6 +2718,30 @@ bool of_DISABLE(vthread_t thr, vvp_code_t cp)
return ! disabled_myself_flag;
}
/*
* Similar to `of_DISABLE`. But will only disable a single thread of the
* specified scope. The disabled thread will be the thread closest to the
* current thread in thread hierarchy. This can either be the current thread,
* either the thread itself or one of its parents.
* This is used for SystemVerilog flow control instructions like `return`,
* `continue` and `break`.
*/
bool of_DISABLE_FLOW(vthread_t thr, vvp_code_t cp)
{
__vpiScope*scope = static_cast<__vpiScope*>(cp->handle);
vthread_t cur = thr;
while (cur && cur->parent_scope != scope)
cur = cur->parent;
assert(cur);
if (cur)
return !do_disable(cur, thr);
return false;
}
/*
* Implement the %disable/fork (SystemVerilog) instruction by disabling
* all the detached children of the given thread.