From df30eda3a37f188acd9e416b28d9942c1c4e61ed Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 16 Apr 2023 08:42:22 -0700 Subject: [PATCH 1/2] 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 From 7973b105ac7683520fcfb726e2a2f57d612a794d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 16 Apr 2023 09:02:45 -0700 Subject: [PATCH 2/2] Add regression test for sub-blocks in `final` procedures Check that sub-blocks containing variables inside of `final` procedures do get executed. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/final3.v | 20 ++++++++++++++++++++ ivtest/regress-vvp.list | 1 + ivtest/vvp_tests/final3.json | 5 +++++ 3 files changed, 26 insertions(+) create mode 100644 ivtest/ivltests/final3.v create mode 100644 ivtest/vvp_tests/final3.json diff --git a/ivtest/ivltests/final3.v b/ivtest/ivltests/final3.v new file mode 100644 index 000000000..b943e9656 --- /dev/null +++ b/ivtest/ivltests/final3.v @@ -0,0 +1,20 @@ +// Check that sub-blocks with variable declarations inside final procedures get +// executed + + +module test; + + final begin + static int x = -1; + for (int i = 0; i < 1; i++) begin + x = i; + end + + if (x === 0) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 2dd09bb7a..95139f51d 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -23,6 +23,7 @@ dffsynth9 vvp_tests/dffsynth9.json dffsynth10 vvp_tests/dffsynth10.json dffsynth11 vvp_tests/dffsynth11.json dumpfile vvp_tests/dumpfile.json +final3 vvp_tests/final3.json macro_str_esc vvp_tests/macro_str_esc.json memsynth1 vvp_tests/memsynth1.json param-width vvp_tests/param-width.json diff --git a/ivtest/vvp_tests/final3.json b/ivtest/vvp_tests/final3.json new file mode 100644 index 000000000..99b4572c5 --- /dev/null +++ b/ivtest/vvp_tests/final3.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "final3.v", + "iverilog-args" : [ "-g2009" ] +}