Goroutines in Verilog

A `goroutine` is a lightweight thread of execution.

```verilog
module main;

  initial begin
    // Calling the function directly
    f("direct");
    
    // Calling the function asynchronously
    fork
      f("goroutine");
    join_none
    
    // Anonymous function call
    fork
      $display("going");
    join_none
    
    // Small delay to allow async tasks to complete
    #10;
    $display("done");
  end
  
  // Function definition
  task f(input reg [7:0] from);
    integer i;
    begin
      for (i = 0; i < 3; i = i + 1) begin
        $display("%s : %0d", from, i);
      end
    end
  endtask

endmodule

Suppose we have a function call f(s). Here’s how we’d call that in the usual way, running it synchronously.

initial begin
  f("direct");
end

To invoke this function asynchronously, use the fork keyword. This new fork will execute concurrently with the calling one.

initial begin
  fork
    f("goroutine");
  join_none
end

You can also start an anonymous function call asynchronously with fork.

initial begin
  fork
    $display("going");
  join_none
end

Our two function calls are running asynchronously now. We use a small delay to wait for them to finish.

initial begin
  #10;
  $display("done");
end

When we run this program, we see the output of the blocking call first, then the output of the other asynchronous calls. The asynchronous tasks’ output may be interleaved, because they are being run concurrently.

$ iverilog -o main main.v && vvp main
direct : 0
direct : 1
direct : 2
goroutine : 0
going
goroutine : 1
goroutine : 2
done

Next we’ll look at a complement to fork in concurrent Verilog programs: channels.