Verilog - implementation of a simple arbiter
Arbiter basic functions
The main function of the arbiter is to determine which source should respond based on the current priority when multiple sources send requests at the same time.
Arbiters are divided into round-robin arbiters and fixed-priority arbiters. The priority of the polling arbiter's response to each source changes with each source's request polling, and ultimately the priority of each source is relatively balanced.
-
The rules of the polling arbiter are: when 0, 1, 2, and N-1 source signal sources send requests to the arbiter at the same time, source 0 has the highest priority initially. When the arbiter responds to source 0, source1 has the highest priority, and so on.
-
The fixed priority arbiter rule is: when 0, 1, 2, and N-1 sources initiate requests at the same time, Source 0 has the highest priority. Even after source 0 is responded to, it is still the highest priority. The priority is according to The serial number gradually decreases.
The polling arbiter and the fixed priority arbiter are implemented similarly in FPGA. The only difference is that the polling arbiter updates the priority after each response to the request, while the fixed priority does not require this step.
The following is an implementation of a simple polling arbiter module. The key points of this implementation are:
- The response priority is determined based on the value of the current priority variable prrty;
- Change the priority prrty after the response is completed.
module arbiter(
input clk ,//时钟
input rst_n ,//复位
input request0 ,//请求0
input request1 ,//请求1
input request2 ,//请求2
input request3 ,//请求3
input end_transaction0,//请求0结束标志
input end_transaction1,//请求1结束标志
input end_transaction2,//请求2结束标志
input end_transaction3,//请求3结束标志
output grant0 ,//响应请求0
output grant1 ,//响应请求1
output grant2 ,//响应请求2
output grant3 //响应请求3
);
localparam S_IDLE = 4'b0000;
localparam S_GNT0 = 4'b0001;
localparam S_GNT1 = 4'b0010;
localparam S_GNT2 = 4'b0100;
localparam S_GNT3 = 4'b1000;
reg [3:0] state ;
reg [3:0] grant ;
reg [3:0] prrty ;//优先级
//grant3, grant2, grant1, grant0
assign {grant3, grant2, grant1, grant0} = grant;
//state
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
state <= S_IDLE;
prrty <= 4'b1000;
end
else
case(state)
S_IDLE:
case(1'b1)
prrty[3]: begin
if(request0)
state <= S_GNT0;
else if(request1)
state <= S_GNT1;
else if(request2)
state <= S_GNT2;
else if(request3)
state <= S_GNT3;
end
prrty[0]: begin
if(request1)
state <= S_GNT1;
else if(request2)
state <= S_GNT2;
else if(request3)
state <= S_GNT3;
else if(request0)
state <= S_GNT0;
end
prrty[1]: begin
if(request2)
state <= S_GNT2;
else if(request3)
state <= S_GNT3;
else if(request0)
state <= S_GNT0;
else if(request1)
state <= S_GNT1;
end
prrty[2]: begin
if(request3)
state <= S_GNT3;
else if(request0)
state <= S_GNT0;
else if(request1)
state <= S_GNT1;
else if(request2)
state <= S_GNT2;
end
endcase
S_GNT0:
if(end_transaction0) begin
prrty <= 4'b0001;
state <= S_IDLE;
end
S_GNT1:
if(end_transaction1) begin
prrty <= 4'b0010;
state <= S_IDLE;
end
S_GNT2:
if(end_transaction2) begin
prrty <= 4'b0100;
state <= S_IDLE;
end
S_GNT3:
if(end_transaction3) begin
prrty <= 4'b1000;
state <= S_IDLE;
end
endcase
end
//grant
always @(*) begin
case(state)
S_IDLE:
grant <= 4'b0000;
S_GNT0:
grant <= 4'b0001;
S_GNT1:
grant <= 4'b0010;
S_GNT2:
grant <= 4'b0100;
S_GNT3:
grant <= 4'b1000;
default:
grant <= 4'b0000;
endcase
end
endmodule
The simulation code is as follows:
//tb_arbiter.v
module tb_arbiter();
reg clk ;
reg rst_n ;
reg request0 ;
reg request1 ;
reg request2 ;
reg request3 ;
reg end_transaction0;
reg end_transaction1;
reg end_transaction2;
reg end_transaction3;
wire grant0 ;
wire grant1 ;
wire grant2 ;
wire grant3 ;
arbiter arbiter_inst(
.clk (clk ),
.rst_n (rst_n ),
.request0 (request0 ),
.request1 (request1 ),
.request2 (request2 ),
.request3 (request3 ),
.end_transaction0 (end_transaction0 ),
.end_transaction1 (end_transaction1 ),
.end_transaction2 (end_transaction2 ),
.end_transaction3 (end_transaction3 ),
.grant0 (grant0 ),
.grant1 (grant1 ),
.grant2 (grant2 ),
.grant3 (grant3 )
);
initial begin
clk = 1'b0;
rst_n = 1'b0; //复位操作
request0 = 1'b0;
request1 = 1'b0;
request2 = 1'b0;
request3 = 1'b0;
end_transaction0 = 1'b0;
end_transaction1 = 1'b0;
end_transaction2 = 1'b0;
end_transaction3 = 1'b0;
#100;
rst_n = 1'b1; //复位完成
#100;
bus_request();
#100
bus_request();
#100;
bus_request();
#100;
bus_request();
#100;
bus_request();
#100;
bus_request();
#100;
bus_request();
#100;
bus_request();
#100;
bus_request();
end
always #10 clk = ~clk;
task bus_request();
begin
request0 = 1'b1;
request1 = 1'b1;
request2 = 1'b1;
request3 = 1'b1;
#20;
request0 = 1'b0;
request1 = 1'b0;
request2 = 1'b0;
request3 = 1'b0;
#200;
if(grant0 == 1'b1)
end_transaction0 = 1'b1;
else if(grant1 == 1'b1)
end_transaction1 = 1'b1;
else if(grant2 == 1'b1)
end_transaction2 = 1'b1;
else if(grant3 == 1'b1)
end_transaction3 = 1'b1;
#20;
end_transaction0 = 1'b0;
end_transaction1 = 1'b0;
end_transaction2 = 1'b0;
end_transaction3 = 1'b0;
end
endtask
endmodule
Simulation results: