轮询仲裁器
轮询仲裁的概念
按照固定的轮询顺序对请求进行仲裁,可以认为是一种动态优先级仲裁,一但某一个请求被授权后,其优先级会降为最低。一般来说默认低位请求的初始优先级最高,往左优先级会依次降低。
如下所示:对于priority来说,数值越小优先级越高。
req grant priority
0000 0000 4321
0001 0001 4321
0011 0010 3214
1000 1000 2143
1001 0001 4321
实现轮询仲裁的思路
直观理解:记当前优先级最高的bit位是N,那么也就是将grant请求授予req中从第 N bit开始的第一个1。
如果使用onehot描述priority,最高优先级的bit为1,其余为0。那么问题就变成了怎么找到从priority中N对应bit位数开始,往左数的第一个1。
先考虑一个简单的问题,从右往左,怎么找到req中的第一个1。
我们可以想到用减法,因为减法会从低位往高位借位(从右往左),如果req减1,req则会找到第一个1进行借位。那么req中的第一个1就会变成0,第一个1左侧高位是原值,右侧低位全1。
那么如果此时将其取法后与原始值相与,则首先第一个1,由于借位变为0,所以取反相与会变成1,左侧因为减1不变化,所以取反相与会变成0,低位因为本身原值是0,所以相与一定为0。所以我们找到了最低位的1。
举个例子:
req req - 1 ~(req - 1)
1010 1001 0110
如果这个理解了,那么很好理解怎么找到priority中的最高位1开始的req中的最低位1。
req & (~(req - priority))
但最开始我们是直观理解,找到这个1就是grant了。
但事实上还有点差异,因为如果priority的1是最高位,按照RR的概念,下次grant应该从req的最低位开始。而按照我们现有的做法,会去找req中priority的最高位右侧的1,但req和priority位宽一样,此时按照现有的逻辑,只会grant给1000,显然不是RR概念。
所以我们可以考虑扩展req的位宽,{req,req},这样当priority为最高位时,此时从最高位往左看{req,req},正好是req的低位。
double_req = {req,req} & (~({req,req} - priority))
因为我们扩展了位宽,所以在grant时,需要缩回去:与一下就好了
grant = double_req[7:4] | double_req[3:0];
完整Verilog代码
其中 arb_switch就是priority,会根据grant动态切换。
module rra #(
parameter N = 4
)(
input clk ,
input rst_n ,
input [N-1:0] req ,
output [N-1:0] grant
);
reg [N-1:0] arb_switch;
wire [2*N-1:0] double_req;
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
arb_switch <= 'd1;
end
else if (|req) begin
arb_switch <= {grant[N-2:0],grant[N-1]};
end
end
assign double_req = {req,req} & (~({req,req} - arb_switch));
assign grant = double_req[N-1:0] | double_req[2*N-1:N];
endmodule
仿真结果

轮询仲裁器及Verilog实现
1067

被折叠的 条评论
为什么被折叠?



