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 <lars@metafoo.de>
This commit is contained in:
parent
b210eb8264
commit
df30eda3a3
|
|
@ -855,6 +855,7 @@ void schedule_final_vthread(vthread_t thr)
|
||||||
struct vthread_event_s*cur = new vthread_event_s;
|
struct vthread_event_s*cur = new vthread_event_s;
|
||||||
|
|
||||||
cur->thr = thr;
|
cur->thr = thr;
|
||||||
|
vthread_mark_final(thr);
|
||||||
vthread_mark_scheduled(thr);
|
vthread_mark_scheduled(thr);
|
||||||
|
|
||||||
schedule_final_event(cur);
|
schedule_final_event(cur);
|
||||||
|
|
|
||||||
|
|
@ -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()
|
void vthread_delay_delete()
|
||||||
{
|
{
|
||||||
if (running_thread)
|
if (running_thread)
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,11 @@ extern vthread_t vthread_new(vvp_code_t sa, __vpiScope*scope);
|
||||||
*/
|
*/
|
||||||
extern void vthread_mark_scheduled(vthread_t thr);
|
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
|
* This function causes deletion of the currently running thread to
|
||||||
* be delayed until after all sync events have been processed for the
|
* be delayed until after all sync events have been processed for the
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue