Rate Limiting in Verilog

Here’s the translation of the Go rate limiting example to Verilog, with appropriate explanations:

Rate limiting is an important mechanism for controlling resource utilization and maintaining quality of service. Verilog can simulate rate limiting using system tasks and behavioral modeling.

module rate_limiter;
  reg [31:0] requests[$];
  reg [31:0] bursty_requests[$];
  integer i;
  
  initial begin
    // First we'll look at basic rate limiting. Suppose
    // we want to limit our handling of incoming requests.
    // We'll serve these requests from a queue.
    for (i = 1; i <= 5; i = i + 1) begin
      requests.push_back(i);
    end
    
    // This timer will trigger every 200 milliseconds.
    // This is the regulator in our rate limiting scheme.
    forever begin
      #200;
      if (requests.size() > 0) begin
        $display("request %0d %0t", requests.pop_front(), $time);
      end
    end
  end
  
  // We may want to allow short bursts of requests in
  // our rate limiting scheme while preserving the
  // overall rate limit. We can accomplish this by
  // using a separate process for bursty requests.
  initial begin
    // Simulate 5 more incoming requests. The first
    // 3 of these will benefit from the burst capability.
    for (i = 1; i <= 5; i = i + 1) begin
      bursty_requests.push_back(i);
    end
    
    // Process bursty requests
    fork
      // Allow initial burst of 3 requests
      for (i = 0; i < 3; i = i + 1) begin
        if (bursty_requests.size() > 0) begin
          $display("bursty request %0d %0t", bursty_requests.pop_front(), $time);
        end
      end
      
      // Then process remaining requests with rate limiting
      forever begin
        #200;
        if (bursty_requests.size() > 0) begin
          $display("bursty request %0d %0t", bursty_requests.pop_front(), $time);
        end
      end
    join
  end
  
  // Run simulation for 2000 time units
  initial #2000 $finish;
endmodule

To run this Verilog simulation, you would typically use a Verilog simulator like ModelSim, VCS, or Icarus Verilog. The exact command might vary depending on your simulator, but it generally looks like this:

$ iverilog rate_limiter.v
$ ./a.out

Running our simulation, we’d see the first batch of requests handled once every ~200 time units as desired:

request 1 200
request 2 400
request 3 600
request 4 800
request 5 1000

For the second batch of requests (bursty requests), we’d see the first 3 handled immediately due to the burst capability, then the remaining 2 with ~200 time unit delays each:

bursty request 1 0
bursty request 2 0
bursty request 3 0
bursty request 4 200
bursty request 5 400

Note that Verilog, being a hardware description language, doesn’t have built-in concepts like goroutines or channels. Instead, we use parallel initial blocks and queues to simulate similar behavior. The timing is controlled using delay statements (#) and the $time system task.