🧵 SystemVerilog fork...join
– Parallel Execution Explained#
In SystemVerilog, the fork...join
construct allows you to execute multiple statements or processes in parallel, similar to threads in software programming. This is especially useful in testbenches, stimulus generation, and concurrent checks.
🔧 Basic Syntax#
fork
statement_1;
statement_2;
statement_3;
join
- All the statements inside
fork...join
start executing simultaneously - The simulation waits for all of them to complete before moving to the next statement after the
join
📌 Variants of join
#
Keyword | Behavior |
---|---|
join | Waits for all threads to finish (blocking) |
join_any | Continues as soon as any one thread finishes |
join_none | Does not wait for any thread; all child processes run in background |
Example with join
:#
fork
#10 $display("A");
#5 $display("B");
join
$display("All done"); // Executes after both A and B
Example with join_any
:#
fork
#20 $display("Slow task");
#5 $display("Fast task");
join_any
$display("One of them finished"); // Executes after first task completes
Example with join_none
:#
fork
#10 $display("Running...");
#20 $display("Still running...");
join_none
$display("No wait, move on immediately");
🔁 disable fork
#
SystemVerilog allows you to terminate all child processes started within a fork...join
block using disable fork;
.
initial begin
fork
forever begin
#1 $display("Looping forever...");
end
#10 disable fork; // Stop the forever loop after 10 time units
join
end
🚨 Synthesis Warning#
fork...join
is not synthesizable- It is intended for testbenches and behavioral modeling only
- Do not use in RTL code
🧪 Typical Use Cases#
Launching parallel stimulus in testbenches
Waiting for multiple monitors or checks
Running concurrent tasks like:
- packet send + scoreboard check
- stimulus + timeout monitor
Creating timeouts or watchdogs with
join_any
✅ Best Practices#
- Use
join
when all parallel threads must complete - Use
join_any
for timeouts or race conditions - Use
join_none
to launch background tasks - Use
disable fork
to gracefully abort all threads
🧠 Summary Table#
Variant | Waits For? | Use Case |
---|---|---|
join | All threads | Synchronized completion |
join_any | First to finish | Timeout or race-based logic |
join_none | No waiting | Background monitoring or delayed checks |
disable fork | Manually terminates all | Force stop child processes (e.g., loops) |
The fork...join
family in SystemVerilog enables powerful concurrent behaviors, especially in UVM and testbench environments. Understanding and using it correctly makes your simulations more realistic, modular, and controlled.
module tb_fork_join_demo;
initial begin
$display("== fork...join Demo ==");
// Basic fork...join: Waits for all to complete
$display("\n[1] fork...join");
fork
#10 $display(" Task A done at %0t", $time);
#5 $display(" Task B done at %0t", $time);
join
$display(" -> All tasks finished at %0t", $time);
// fork...join_any: Continues after first finishes
$display("\n[2] fork...join_any");
fork
#20 $display(" Slow task done at %0t", $time);
#5 $display(" Fast task done at %0t", $time);
join_any
$display(" -> One task finished at %0t", $time);
// fork...join_none: Moves on immediately
$display("\n[3] fork...join_none");
fork
#10 $display(" Background A at %0t", $time);
#20 $display(" Background B at %0t", $time);
join_none
$display(" -> Proceeding immediately at %0t", $time);
// fork with disable fork
$display("\n[4] fork with disable fork");
fork
forever begin
#1 $display(" Looping... %0t", $time);
if($time == 100) break;
end
join
$display("== Simulation done at %0t ==", $time);
#10 $finish;
end
endmodule