From df30eda3a37f188acd9e416b28d9942c1c4e61ed Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 16 Apr 2023 08:42:22 -0700 Subject: [PATCH] vvp: Handle %fork in `final` procedures In the current implementation a `%fork` instruction in a final block will get scheduled, but never executed. And while SystemVerilog requires a `final` procedure to execute in 0 time and so no SystemVerilog `fork` is allowed inside of it, there are some other scenarios where iverilog generates `%fork` statements. For example when declaring variables in a sub-block a sub-scope with its own thread is is used to allocate the storage for those variables and `%fork` is used to execute the child thread. E.g. the following, while being valid SystemVerilog, will never execute the loop because the generated code will implement the loop as a child thread being executed by a `%fork` statement. ``` final for (int i = 0; i < 10; i++) $display(i); ``` To mitigate this treat final statements the same as functions and rather than scheduling a child thread, execute it immediately when using the `%fork` statement. Signed-off-by: Lars-Peter Clausen --- vvp/schedule.cc | 1 + vvp/vthread.cc | 13 +++++++++++++ vvp/vthread.h | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/vvp/schedule.cc b/vvp/schedule.cc index 78920dee9..961aa36e6 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -855,6 +855,7 @@ void schedule_final_vthread(vthread_t thr) struct vthread_event_s*cur = new vthread_event_s; cur->thr = thr; + vthread_mark_final(thr); vthread_mark_scheduled(thr); schedule_final_event(cur); diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 2b35315b0..02c7c179d 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -833,6 +833,19 @@ void vthread_mark_scheduled(vthread_t thr) } } +void vthread_mark_final(vthread_t thr) +{ + /* + * The behavior in a final thread is the same as in a function. Any + * child thread will be executed immediately rather than being + * scheduled. + */ + while (thr != 0) { + thr->i_am_in_function = 1; + thr = thr->wait_next; + } +} + void vthread_delay_delete() { if (running_thread) diff --git a/vvp/vthread.h b/vvp/vthread.h index 75d7929c8..1658c6839 100644 --- a/vvp/vthread.h +++ b/vvp/vthread.h @@ -51,6 +51,11 @@ extern vthread_t vthread_new(vvp_code_t sa, __vpiScope*scope); */ extern void vthread_mark_scheduled(vthread_t thr); +/* + * This function marks the thread as being a final procedure. + */ +extern void vthread_mark_final(vthread_t thr); + /* * This function causes deletion of the currently running thread to * be delayed until after all sync events have been processed for the