提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
一、固定优先级仲裁器(Fixed Priority Arbiter)
三、权重循轮询仲裁器(Weighted Round Robin Arbiter)
前言
常用仲裁器的简单总结,方便自己后续查询和复习
一、固定优先级仲裁器(Fixed Priority Arbiter)
当有多个主设备发起请求时,需要对多个请求进行仲裁,一般同一时刻只有一个主设备可以控制总线。
固定优先级:优先级是固定的,多个主设备同时发起请求,每次都会响应优先级最高的那个主设备。例:A>B>C或者A<B<C
1、case/if语句实现
信号固定位宽,最高位的优先级最高代码如下:
高位优先级最高
module fixed_pri_arb(
input [3:0] request,
output [3:0] grant_reg
);
//case语句会被综合成串行结构
always@(*) begin
case(1'b1)
request[0]: grant_reg = 4'b1000;
request[1]: grant_reg = 4'b0100;
request[2]: grant_req = 4'b0010;
request[3]: grant_req = 4'b0001;
default: grant_req = 4'b0000;
endcase
end
//casez语句实现
always@(*) begin
casez(request)
4'b1???: grant_reg = 4'b1000;
4'b01??: grant_reg = 4'b0100;
4'b001?: grant_req = 4'b0010;
4'b0001: grant_req = 4'b0001;
default: grant_req = 4'b0000;
endcase
end
//此处也可以使用if-else语句
always@(*) begin
if(request[3])
grant_reg = 4'b1000;
else if(request[2])
grant_reg = 4'b0100;
else if(request[1])
grant_reg = 4'b0010;
else if(request[0])
grant_reg = 4'b0001;
else
grant_reg = 4'b0000;
end
endmodule
2、for循环语句实现参数化
信号位宽参数化,代码如下:
低位优先级最高
module fixed_pri_arb #(
parameter REQ_WIDTH = 16
)(
input [REQ_WIDTH-1:0] req,
output [REQ_WIDTH-1:0] grant
);
//记录低位是否已经有了request
reg [REQ_WIDTH-1:0] pre_req;
//实现低位优先级最高
always@(*) begin
grant[0] = req[0];
pre_req[0] = req[0];
for(genvar i=1; i<REQ_WIDTH; i=i+1) begin
grant[i] = req[i] & ~pre_req[i-1];
pre_req[i] = req[i] | pre_req[i-1];
end
end
endmodule
要实现高位优先级最高,把req和grant重新排布一下即可,代码如下:
reg [REQ_WIDTH-1:0] req_inverse;
reg [REQ_WIDTH-1:0] grant_inverse;
always(*) begin
for(genvar i=0; i<REQ_WIDTH; i=i+1) begin
req_inverse[i] = req[REQ_WIDTH-1-i];
grant[i] = grant_inverse[REQ_WIDTH-1-i];
end
end
3、展开for循环的变体
低位优先级最高,代码如下:
module fixed_pri_arb #(
paramter REQ_WIDTH= 4
)(
input [REQ_WIDTH-1:0] req,
output [REQ_WIDTH-1:0] grant
);
wire [REQ_WIDTH-1:0] pre_req;
//pre_req[i+1]由req[i] | pre[i]决定
//效果是pre_req保存的是req第一个1位置以后的高位都为1
assign pre_req[0] = 0;
assign pre_req[REQ_WIDTH-1:1] = req[REQ_WIDTH-2:0] | pre_req[REQ_WIDTH-2:0];
assign grant = req & ~pre_req;
endmodule
4、补码相与法
低位优先级最高,即从低位到高位找出第一个1出现的req请求被grant。
保留一个数中最低位的1,其他置0,可以用原码&补码的方式实现。
原理如下:补码为原码取反+1得到。只有第一个1的位置,补码有进位变1,相与后不为零。
原码 | 0001 | 0010 | 0011 | 0100 |
补码 | 1111 | 1110 | 1101 | 1100 |
reqeust当成原码,求补码,后相与,代码如下:
module fixed_pri_arb #(
parameter REQ_WIDTH = 4
)(
input [REQ_WIDTH-1:0] req;
output [REQ_WIDTH-1:0] grant
);
assign grant = req & (~req + 1'b1);
endmodule
request 当成补码,求原码,后相与;(低位优先级最高)
可以通过重排request和grant信号的方式(同上),实现高位最高优先级
代码如下:
module fixed_pri_arb #(
parameter REQ_WIDTH = 4
)(
input [REQ_WIDTH-1:0] req,
output [REQ_WIDTH-1:0] grant
);
assign grant = req & (~(req - 1'b1));
endmodule
二、轮询仲裁器(Round Robin Arbiter)
轮询机制:当一个req获得grant后,优先级在接下来的仲裁中变得最低。每一响应完一个设备,都会对优先级进行更新。
有以下两种实现方式:
1、优先级仲裁器+优先级更新
A & ~(A-base)的结果是保留base对应位的A左边第一个1,其中base为onehot;每次仲裁后,base权重最高位左移进行更新。
module round_robin_arb #(
parameter REQ_WIDTH = 4
)(
input clk,
input rst_n,
input [REQ_WIDTH-1:0] req,
output [REQ_WIDTH-1:0] grant
);
//signals
reg [REG_WIDTH-1:0] base;
wire [2*REG_WIDTH-1:0] double_grant;
assign double_grant = {req, req} & (~({req, req} - base));
assign grant = double_grant[2*REQ_WIDTH-1:REQ_WIDTH] | double_grant[REQ_WIDTH-1:0];
always@(posedge clk or negedge rst_n) begin
if (!rst_n)
base <= {{REQ_WIDTH-1{1'b0}}, 1'b1}; //默认最低位最高优先级
else if (|req)
base <= {grant[REQ_WIDTH-2:0], grant[REQ_WIDTH-1]};
end
endmodule
2、固定优先级仲裁器+MASK Request
思路:如果某一个req被grant,就把该req请求mask掉,仲裁剩下req,并且权重保持不变;当所有的req都被仲裁完了,再载入新的mask。
展开for循环的固定优先级仲裁器中,pre_req信号实现:如果req的第i位为1,那么pre_req从第i+1位开始都是1,从第0位到第i位都是0。即pre_req就是所需要的mask。只需要把当前的req和上一拍的pre_req 与起来,得到mask后的req。
module round_robin_arb #(
parameter REQ_WIDTH = 4
)(
input clk,
input rst_n,
input [REQ_WIDTH-1:0] req,
output [REQ_WIDTH-1:0] grant
);
wire [REQ_WIDTH-1:0] req_masked;
wire [REQ_WIDTH-1:0] mask_higher_pri_reqs;
wire [REQ_WIDTH-1:0] grant_masked;
wire [REQ_WIDTH-1:0] unmask_higher_pri_reqs;
wire [REQ_WIDTH-1:0] grant_unmasked;
wire no_req_masked;
reg [REQ_WIDTH-1:0] pointer_reg;
//simple priority arbitration for masked portion
assign req_masked = req & pointer_reg;
assign mask_higher_pri_reqs[0] = 1'b1;
assign mask_higher_pri_reqs[REQ_WIDTH-1:1] = req_masked[REQ_WIDTH-2:0] |
mask_higher_reqs[REQ_WIDTH-2:0];
assign grant_masked = req_masked & (~mask_higher_pri_reqs);
//simple priority arbitration for unmasked portion
assign unmask_higher_pri_reqs[0] = 1'b0;
assign unmask_higher_pri_reqs[REQ_WIDTH-1:1] = req[REQ_WIDTH-2:0] |
unmask_higher_pri_reqs[REQ_WIDTH-2:0];
assign garnt_unmasked = req & (~unmask_higher_pri_reqs);
//use grant_masked if there is any there, otherwise use grant_unmasked.
assign no_req_masked = ~(|req_masked);
assign grant = ({REQ_WIDTH{no_req_masked}} & grant_unmasked) | grant_masked;
//pointer update
always@(posedge clk or negedge rst_n) begin
if (!rst_n)
pointer_reg <= {REQ_WIDTH{1'b1}};
else if (|req_masked)
pointer_reg <= mask_higher_pri_reqs;
else begin
if (|req) //only update if there's a req
pointer_reg <= unmask_higher_reqs;
end
end
endmodule
思路:把mask和unmask仲裁器分别实现出来,然后利用req_masked等于0条件进行grant信号的mux。
问题记录:直接先把reg_masked和req先mux出来,再送进仲裁器,可以减少一个仲裁器数量?
三、权重循轮询仲裁器(Weighted Round Robin Arbiter)
在轮询仲裁基础上,不同权重的req会得到不同的访问次数,非公平的轮询机制
有两种解决思路:
1、基于grant进行轮询
考虑权重,一般做法是给每个用户固定的仲裁次数,然后每个用户每仲裁一次计数一次。
因此,完成一次仲裁后,不能立即对grant进行循环左移,而是判断当前用户可仲裁次数是否已经用完,若已经用完,则grant_base进行跳转;反之,如果当前请求停止仲裁,并且其他请求到来,依然跳转,否则保持不变。
module weight_rr_arb #(
parameter REQ_WIDTH = 4,
parameter CNT_WIDTH = 5,
parameter INIT_GRANT = {{REQ_WIDTH-1{1'b0}}, 1'b1},
parameter WEIGHT_WIDTH = CNT_WIDTH*REQ_WIDTH
)(
input clk,
input rst_n,
input [REQ_WIDTH-1:0] req,
input [WEIGHT_WIDTH-1:0] weight,
output [REQ_WIDTH-1:0] grant
);
reg [REQ_WIDTH-1:0] grant_base;
wire [REQ_WIDTH*2-1:0] double_req;
wire [REQ_WIDTH*2-1:0] double_grant;
reg [CNT_WIDTH-1:0] priority_cnt [REQ_WIDTH-1:0];
wire [REQ_WIDTH-1:0] cnt_over;
wire [REQ_WIDTH-1:0] round_en;
wire req_flag;
assign req_flag = |req;
generate
for(genvar i=0; i<REQ_WIDTH; i=i+1) begin
assign cnt_over[i] = priority_cnt[i] == weight[CNT_WIDTH*(i+1)-1-:CNT_WIDTH];
assign round_en[i] = cnt_over[i] | ((priority_cnt[i] != 0) & (~req[i]));
always@(posedge clk or negedge rst_n) begin
if (!rst_n)
priority_cnt[i] <= {CNT_WIDTH{1'b0}};
else if (grant[i]) //有grant产生:被grant进行计数加1,未被grant清0
priority_cnt[i] <= priority_cnt[i] + 1'b1;
else
priority_cnt[i] <= {CNT_WIDTH{1'b0}};
end
end
endgenerate
always@(posedge clk or negedge rst_n) begin
if (!rst_n)
grant_base <= INIT_GRANT;
else if (|round_en & req_flag)
grant_base <= {grant_base[REQ_WIDTH-2:0], grant_base[REQ_WIDTH-1]};
end
assign double_req = {req, req};
assign double_grant = double_req & (~(double_req - grant_base));
assign grant= double_grant[REQ_WIDTH*2-1:REQ_WIDTH] | double_grant[REQ_WIDTH-1:0];
endmodule
2、基于request进行轮询
权重没有改变仲裁的选择方法,仅仅只会改变mask跳转的判断条件。
标签:req,优先级,grant,REQ,WIDTH,verilog,reg,仲裁 From: https://blog.csdn.net/m0_62869075/article/details/142134185