Verilog Code for Round Robin Arbiter: Syntax and Example
A
round robin arbiter in Verilog cycles through requests fairly, granting access one at a time in order. It uses a pointer to track the last granted request and moves to the next request on each clock cycle. The code typically includes input request signals, output grant signals, and a register to hold the current grant position.Syntax
The round robin arbiter uses inputs for requests and outputs for grants. A register stores the current grant position to ensure fairness. On each clock cycle, it checks requests starting from the next position after the last grant and grants the first active request found.
- clk: Clock signal to synchronize grants.
- rst: Reset signal to initialize the grant pointer.
- req: Input vector of request signals.
- grant: Output vector indicating which request is granted.
- current_grant: Register holding the last granted index.
verilog
module round_robin_arbiter #(parameter WIDTH = 4) ( input wire clk, input wire rst, input wire [WIDTH-1:0] req, output reg [WIDTH-1:0] grant ); reg [$clog2(WIDTH)-1:0] current_grant; integer i; always @(posedge clk or posedge rst) begin if (rst) begin current_grant <= 0; grant <= 0; end else begin grant <= 0; for (i = 1; i <= WIDTH; i = i + 1) begin if (req[(current_grant + i) % WIDTH]) begin grant[(current_grant + i) % WIDTH] <= 1'b1; current_grant <= (current_grant + i) % WIDTH; disable for; end end end end endmodule
Example
This example shows a 4-request round robin arbiter. It grants requests fairly in a cycle, moving to the next request after each grant. The testbench applies requests and shows which request is granted each clock cycle.
verilog
module tb_round_robin_arbiter();
reg clk = 0;
reg rst = 1;
reg [3:0] req = 4'b0000;
wire [3:0] grant;
round_robin_arbiter #(4) arbiter (
.clk(clk),
.rst(rst),
.req(req),
.grant(grant)
);
always #5 clk = ~clk; // 10 time units clock period
initial begin
$monitor($time, " ns: req=%b grant=%b", req, grant);
#10 rst = 0;
// Cycle through requests
req = 4'b0001; #10;
req = 4'b0011; #10;
req = 4'b0110; #10;
req = 4'b1000; #10;
req = 4'b1111; #10;
req = 4'b0000; #10;
$finish;
end
endmoduleOutput
10 ns: req=0001 grant=0001
20 ns: req=0011 grant=0010
30 ns: req=0110 grant=0100
40 ns: req=1000 grant=1000
50 ns: req=1111 grant=0001
60 ns: req=0000 grant=0000
Common Pitfalls
Common mistakes include:
- Not wrapping the grant pointer correctly, causing out-of-range errors.
- Granting multiple requests at once instead of only one.
- Not resetting the grant pointer on reset, leading to unpredictable grants.
- Using blocking assignments in sequential logic, which can cause simulation mismatches.
Always use non-blocking assignments (<=) inside always @(posedge clk) blocks and ensure the grant pointer wraps using modulo arithmetic.
verilog
/* Wrong: blocking assignment and no wrap-around */ always @(posedge clk) begin if (req[current_grant]) grant = 1 << current_grant; // blocking assignment else current_grant = current_grant + 1; // no modulo wrap end /* Right: non-blocking and modulo wrap */ always @(posedge clk) begin if (req[current_grant]) begin grant <= 1 << current_grant; end else begin current_grant <= (current_grant + 1) % WIDTH; end end
Quick Reference
- Use a pointer to track last granted request for fairness.
- Check requests starting from the next pointer position.
- Grant only one request per clock cycle.
- Reset pointer on system reset.
- Use modulo arithmetic to wrap pointer.
Key Takeaways
A round robin arbiter grants requests one at a time in a rotating order to ensure fairness.
Use a pointer and modulo arithmetic to cycle through requests correctly.
Always reset the grant pointer and use non-blocking assignments in sequential logic.
Grant only one request per clock cycle to avoid conflicts.
Test with various request patterns to verify correct round robin behavior.