Chapter3. 仲裁器专题
Chapter3. 仲裁器专题
导图
本专题内容总结自李虹江老师的IC加油站公众号,李老师的讲的内容十分精彩,除了仲裁器还包括异步FIFO、跨时钟域处理,讲的十分透彻,受益匪浅。
Fixed Priority Arbiter
- 默认req中最低位的优先级最高
先来最优写法,req & (~(req - 1))
直接得到req
中最低为1的位置,就是gnt
。
为什么会有这个性质呢?
~(req - 1)其实就是req的补码,一个数的原码与补码相与。得到的就是一个独热码,onehot code中为1的位置就是这个数最低的1的位置。精彩!
module priority_arbiter
#(
parameter REQ_WIDTH = 16
)
(
input [REQ_WIDTH-1:0] req,
output [REQ_WIDTH-1:0] gnt
);
// best solution
assign gnt = req & (~(req - 1));
endmodule
`timescale 1ns/1ps
module tb;
reg clk, rst_n;
initial begin
clk = 1'b0;
#5 clk = 1'b1;
forever #5 clk = ~clk;
end
reg [15:0] req;
initial begin
while(1)begin
#20
req = $random;
end
end
wire [15:0] gnt;
priority_arbiter inst
(req, gnt);
initial begin
$dumpfile("showmebug.vcd");
$dumpvars(0, tb);
#600
end
endmodule
Fixed Priority Arbiter的另外两种写法
- 思路就是用
pre_req
保存req当前位和前一位是否为1(被req过),如果第i位有了request,那么第i+1位到最高位的pre_req都是1
module priority_arbiter
#(
parameter REQ_WIDTH = 4
)
(
input [REQ_WIDTH-1:0] req,
output reg [REQ_WIDTH-1:0] gnt
);
reg [REQ_WIDTH-1:0] pre_req;
integer i;
always @(*)begin
// pre_req记录低位是否有req
pre_req[0] = req[0];
gnt[0] = req[0];
for(i = 1; i < REQ_WIDTH; i = i + 1)begin
gnt[i] = req[i] & !pre_req[i-1];
pre_req[i] = req[i] | pre_req[i-1];
end
end
endmodule
// 另一种写法,跟上面的思路一样,就是把上面for用assign来实现。
module priority_arbiter_m2
#(
parameter REQ_WIDTH = 4
)
(
input [REQ_WIDTH-1:0] req,
output [REQ_WIDTH-1:0] gnt
);
wire [REQ_WIDTH-1:0] pre_req;
assign pre_req = req[0];
assign pre_req[REQ_WIDTH-1:1] = req[REQ_WIDTH-2:0] | pre_req[REQ_WIDTH-2:0];
assign gnt = req & !pre_req;
endmodule
noob写法
为什么这种case的写法是可以的?因为在verilog中,case的执行只执行其中一个条件,执行完该条件就跳出case,不像C中的case,如果不加continue就会继续判断下面的条件。
module fixed_arbiter
(
input [3:0] req,
output reg [3:0] gnt
);
always @(*)begin
case(1'b1)
req[0]: gnt = 4'b0001;
req[1]: gnt = 4'b0010;
req[2]: gnt = 4'b0100;
req[3]: gnt = 4'b1000;
endcase
end
endmodule
Round Robin Arbiter
RR仲裁器的仲裁逻辑
- priority是变化的
- 变化的规则为,初始priority是3210(数字越小优先级越高),如果某位被grant了,那么那一位的优先级变为最低(3),同时那一位左边的优先级从低到高排列到最高位,然后“绕回”到被gnt到那位的右边。
- 这种绕圈也因此被称为_round robin_
- 比如说初始priority是3210,倒数第二位被gnt了,那么优先级将会变化为1032
RR仲裁器的实现思路
更换base,req不变思路
- 实现一个固定优先级的fixed arbiter,它的输入除了有req,还有base,表示输入的优先级
- 那么RR仲裁器实现只需要每次gnt之后更新base,即可实现
- base的格式是什么呢?优先级最高的那一位为1
- 那么base是如何更新的呢?由于base是one hot code,gnt也是one hot,根据rr仲裁器的逻辑,只需要将gnt循环左移一位就是下一个cycle的base了
module round_robin_arbiter
#(
parameter NUM_REQ = 4
)
(
input clk,
input rst_n,
input [NUM_REQ-1:0] req,
output [NUM_REQ-1:0] gnt
);
reg [NUM_REQ-1:0] hist_q;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
hist_q <= 1'b1;
else begin
if(|req)
hist_q <= {gnt[NUM_REQ-2:0, gnt[NUM_REQ-1]]} // 循环左移更新base
end
end
endmodule
module arbiter_base
#(
parameter NUM_REQ = 4
)
(
input [NUM_REQ-1:0] req,
input [NUM_REQ-1:0] base,
output [NUM_REQ-1:0] gnt
);
// 位宽扩展,防止-base不够减
wire [2*NUM_REQ-1:0] double_req;
wire [2*NUM_REQ-1:0] double_gnt;
assign double_req = {req, req};
assign double_gnt = double_req | (~(double_req - base));
assign gnt = double_gnt[NUM_REQ-1:0] | double_gnt[2*NUM_REQ-1:NUM_REQ];
endmodule
mask掉req,不改变base
module round_robin_arbiter
#(
parameter N = 16
)
(
input clk,
input rst,
input [N-1:0] req,
output [N-1:0] grant
);
reg [N-1:0] req_masked;
reg [N-1:0] mask_higher_pri_reqs;
reg [N-1:0] unmask_higher_prt_reqs;
reg [N-1:0] grant_unmasked;
reg [N-1:0] grant_masked;
reg no_req_masked;
reg [N-1:0] pointer_reg;
assign req_masked = req & pointer_reg; // req 跟 pre_req相与,从req最低位1位置开始,到最高位都是1.
assign mask_higher_pri_reqs[N-1:1] = mask_higher_pri_reqs[N-2:0] | req_masked[N-2:0];
assign mask_higher_pri_reqs[0] = 1'b0;
assign grant_masked = req_masked[N-1:0] & ~mask_higher_pri_reqs[N-1:0];
assign unmask_higher_prt_reqs[N-1:1] = unmask_higher_prt_reqs[N-2:0] | req[N-2:0];
assign unmask_higher_prt_reqs[0] = 1'b0;
assign grant_unmasked[N-1:0] = req[N-1:0] & ~unmask_higher_prt_reqs[N-1:0];
assign no_req_masked = ~(|req_masked);
assign grant = ({N{no_req_masked}} & grant_unmasked) | grant_masked;
always @(posedge clk)begin
if(rst_n)
pointer_reg <= {N{1'b1}};
else begin
if(|req_masked)
pointer_reg <= mask_higher_pri_reqs;
else begin
if(|req)
pointer_reg <= unmask_higher_prt_reqs;
else
pointer_reg <= pointer_reg;
end
end
end
endmodule