仲裁器(arbiter)在FPGA主要用于多个source源同时发出请求时,根据相应的优先级来响应哪一个source。常用的仲裁器分为轮询仲裁器(Round-Robin)和固定优先级仲裁器(Fixed-Priority)。
Round-Robin Arbiter(轮询调度仲裁器)
这是一个四输入的仲裁
module arb_comb4(
input [1:0] cur_arb_id,
input [3:0] arb_req,
input arb_en,
output reg [1:0] nxt_arb_id
);
always @ (*) begin
if(arb_en) begin
case(cur_arb_id)
2'd0 : case(1'b1)
arb_req[1]: nxt_arb_id = 2'd1;
arb_req[2]: nxt_arb_id = 2'd2;
arb_req[3]: nxt_arb_id = 2'd3;
arb_req[0]: nxt_arb_id = 2'd0;
default : nxt_arb_id = 2'd0;
endcase
2'd1 : case(1'b1)
arb_req[2]: nxt_arb_id = 2'd2;
arb_req[3]: nxt_arb_id = 2'd3;
arb_req[0]: nxt_arb_id = 2'd0;
arb_req[1]: nxt_arb_id = 2'd1;
default : nxt_arb_id = 2'd1;
endcase
2'd2 : case(1'b1)
arb_req[3]: nxt_arb_id = 2'd3;
arb_req[0]: nxt_arb_id = 2'd0;
arb_req[1]: nxt_arb_id = 2'd1;
arb_req[2]: nxt_arb_id = 2'd2;
default : nxt_arb_id = 2'd2;
endcase
2'd3 : case(1'b1)
arb_req[0]: nxt_arb_id = 2'd0;
arb_req[1]: nxt_arb_id = 2'd1;
arb_req[2]: nxt_arb_id = 2'd2;
arb_req[3]: nxt_arb_id = 2'd3;
default : nxt_arb_id = 2'd3;
endcase
default : nxt_arb_id = 2'd0;
endcase
end
else begin
nxt_arb_id = cur_arb_id;
end
end
endmodule
///
// Discription:
// Bus Polling Arbitor (BPA)
// 总线上挂3个信号A,B,C,仲裁信号grant[1:0]。
// grant[1:0]=2’b00 A获得总线
// grant[1:0]=2’b01 B获得总线
// grant[1:0]=2’b10 C获得总线
// 总线轮询算法a.如果当前只有一个信号请求,则处理.
// b.如果没有请求,那么A获得总线.
// c.如果同时有多个信号请求,考虑上一个请求信号,
// 如果上一个请求信号是A,那么轮询的是BCA,
// 如果上一个请求信号是B,那么轮询的是CAB,
// 如果上一个请求信号是C,那么轮询的是ABC
//
module bus_arbitor(
input clk_i,
input en_i,
input sig_a_i,
input sig_b_i,
input sig_c_i,
output reg [1:0] grant_o
);
reg [1:0] ls;
parameter s_null = 3'b000;
parameter s_a = 3'b001;
parameter s_b = 3'b010;
parameter s_c = 3'b100;
parameter s_ab = 3'b110;
parameter s_bc = 3'b011;
parameter s_ac = 3'b101;
parameter s_abc = 3'b111;
always @ (posedge clk_i or negedge en_i) begin
if(!en_i) begin
grant_o <= 2'b11;
ls <= s_null;
end
else begin
case({sig_a_i,sig_b_i,sig_c_i})
s_null : begin
grant_o <= 2'b00;
ls <= s_a;
end
s_a : begin
grant_o <= 2'b00;
ls <= s_a;
end
s_b : begin
grant_o <= 2'b01;
ls <= s_b;
end
s_c : begin
grant_o <= 2'b10;
ls <= s_c;
end
s_ab : begin
case(ls)
s_a : begin
grant_o <= 2'b01;
ls <= s_b;
end
s_b : begin
grant_o <= 2'b00;
ls <= s_a;
end
s_c : begin
grant_o <= 2'b00;
ls <= s_a;
end
endcase
end
s_bc : begin
case(ls)
s_a : begin
grant_o <= 2'b01;
ls <= s_b;
end
s_b : begin
grant_o <= 2'b10;
ls <= s_c;
end
s_c : begin
grant_o <= 2'b01;
ls <= s_b;
end
endcase
end
s_ac : begin
case(ls)
s_a : begin
grant_o <= 2'b10;
ls <= s_c;
end
s_b : begin
grant_o <= 2'b10;
ls <= s_c;
end
s_c : begin
grant_o <= 2'b00;
ls <= s_a;
end
endcase
end
s_abc : begin
case(ls)
s_a : begin
grant_o <= 2'b01;
ls <= s_b;
end
s_b : begin
grant_o <= 2'b10;
ls <= s_c;
end
s_c : begin
grant_o <= 2'b00;
ls <= s_a;
end
endcase
end
default : begin
grant_o <= 2'b00;
ls <= s_a;
end
endcase
end
end
endmodule
轮询仲裁的规则是当0、1、2、、、、N-1个source信号源同时向仲裁发出请求时,初始情况下source0的优先级最高,当仲裁器响应了source0之后,source1的优先级最高,依次类推。
假设上一次的Arbiter结果为0000 0001,则下一次的结果应该为1~7位中的最低请求位。
比如:
以表格最后一行为例:请求A = 0000 0110,上一次的Round-Robin结果为 B = 0000 0001,需要求本次的Round-Robin结果C。
计算过程
解:
A = 0000 0110 , B = 0000 0001
AA = 0000 0110 0000 0110
AA& ~(AA-B)
=(0000 0110 0000 0110)& ~(0000 0110 0000 0110 - 0000 0001)
=(0000 0110 0000 0110)& ~(0000 0110 0000 0101)
=(0000 0110 0000 0110)& (1111 1001 1111 1010)
= 0000 0000 0000 0010
= DE
D = 0000 0000 , E = 0000 0010
C = D|E = 0000 0010
综上所述,本次Round-Robin Arbiter 的计算结果为C = 0000 0010,与预期结果一致,符合要求。
注意事项:
请求输入不可以为全零,否则通用计算公式无效。
请求输入不能包含上一次结果位。比如上一次Round-Robin 结果为0001,如果本次请求为0111,那么应先进行 0111 - 0001 = 0110计算,然后再将0110 当做请求套入公式中。
固定优先级仲裁器
Fixed-priority Arbiter顾名思义当0、1、2、、、N-1个source同时发起request,Source 0的优先级最高,即便source0被相应完后,仍为最高优先级,其中优先级按照序号逐渐降低。
2.固定优先级仲裁实现
固定优先级仲裁器在FPGA实现与轮询仲裁器类似,唯一不同的是轮询仲裁在每次响应完request后会对优先级进行更新,而固定优先级则不需要此步骤。