Waitgroups in Verilog

Our example demonstrates the concept of synchronization in Verilog using tasks and events. While Verilog doesn’t have direct equivalents to goroutines or WaitGroups, we can simulate similar behavior using parallel blocks and events.

module waitgroups;

  // This is the task we'll run in every parallel block
  task automatic worker(input integer id);
    $display("Worker %0d starting", id);
    
    // Delay to simulate an expensive task
    #1000;
    $display("Worker %0d done", id);
  endtask

  event all_done;
  integer count;

  initial begin
    count = 0;

    // Launch several parallel blocks
    fork
      begin
        worker(1);
        count = count + 1;
        if (count == 5) -> all_done;
      end
      begin
        worker(2);
        count = count + 1;
        if (count == 5) -> all_done;
      end
      begin
        worker(3);
        count = count + 1;
        if (count == 5) -> all_done;
      end
      begin
        worker(4);
        count = count + 1;
        if (count == 5) -> all_done;
      end
      begin
        worker(5);
        count = count + 1;
        if (count == 5) -> all_done;
      end
    join_none

    // Wait for all workers to finish
    @(all_done);
    $display("All workers have finished");
    $finish;
  end

endmodule

To run this Verilog code, you would typically use a Verilog simulator such as Icarus Verilog or ModelSim. The exact command might vary depending on your simulator, but it could look something like this:

$ iverilog -o waitgroups waitgroups.v
$ vvp waitgroups
Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 4 starting
Worker 5 starting
Worker 1 done
Worker 2 done
Worker 3 done
Worker 4 done
Worker 5 done
All workers have finished

In this Verilog version:

  1. We define a worker task that simulates work with a delay.

  2. Instead of a WaitGroup, we use an event all_done and a counter count to track when all workers are finished.

  3. We use a fork-join_none block to launch multiple parallel blocks, each running a worker.

  4. Each worker increments the count when it’s done. The last worker to finish triggers the all_done event.

  5. The main thread waits for the all_done event before finishing the simulation.

Note that the order of workers starting and finishing may vary between runs, just like in the original example. This approach demonstrates basic synchronization in Verilog, although it’s not as flexible as Go’s WaitGroups for more complex scenarios.