仲裁器(arbiter) 的主要功能是,多个source源同时发出请求时,根据当前的优先级来判断应响应哪一个source。
仲裁器分为轮询优先级仲裁器(Round-Robiin)和固定优先级仲裁器(Fixed-Priority)。轮询仲裁器对各个source的响应优先级随各个source请求轮询变化,最终对各个source的优先级是较为均衡的。
轮询仲裁器的规则是:当0、1、2、、、N-1个source信号源同时向仲裁器发出请求时,初始情况下source 0的优先级最高,当仲裁器响应了source0后,source1的优先级最高,依次类推。
固定优先级仲裁器规则是:当0、1、2、、、N-1个source同时发起request,Source 0的优先级最高,即便source0被相应完后,仍为最高优先级,其中优先级按照序号逐渐降低。
轮询仲裁器和固定优先级仲裁器在FPGA实现的类似,唯一不同的是轮询仲裁在每次响应完request后会对优先级进行更新,而固定优先级则不需要此步骤。
下面是一个简单轮询仲裁器模块的实现方案。该实现方案的关键点是:
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
仿真代码如下:
//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