当多个源和用户需要共享同一资源时,需要某种仲裁形式,使得所有用户基于一定的规则或算法得到获取或访问共享资源的机会。
第一种方法是为每个用户分配一个变量,该变量决定了在一个轮询周期内该用户能够得到许可(被授权)的次数。该变量是可以通过软件编程进行修改的,因此其轮询权重也可以相应调整。
例如,有三个用户,agent0权重为3、agentl权重为2、agent2权重为1。在一个轮询周期中,agent0最大可以得到3次许可,agent1可以得到2次许可,agent22可以得到1次许可。在一个轮询周期开始时,变量N_agnt0、N_ agnt1和Nagnt_2分别被预置为3、2和1。每次轮询后对应的变量值减1,一个轮询周期结束后,这些变量会被重新设置为预置的初值。
如果所有的用户同时请求,仲裁器将按照下面两种方式给予许可:
一个用户可以连续地获得许可,获得许可的次数由预置的权重值决定。当所有用户同时发出请求时,许可序列依次为:
在所有存在许可机会的用户之间进行公平轮询,在一个循环周期内,不用用户得到的总许可机会由预置的权重值决定。当所有请求同时发生时,许可序列为:
在另一种方案中,可软件编程的定时器被用于分配权重。一个仲裁周期开始时,定时器数值被加载到本地变量中。当一个用户获得许可后,本地变量减1,直到减至0为止。如果被轮询的用户没有完成操作,仲裁器停止对当前用户的许可并根据优先级轮询下一个用户。
接下来,我们给出了采用WRR轮询方案的Verilog RTL代码及仿真结果,它采用的是第一种许可方式,序列为A,A,A,B,B,C…。
下面是采用第二种权重轮询方式的Verilog代码及仿真结果,当所有用户都同时发出请求时,轮询序列为:
参考《verilog高级数字系统设计技术与实例分析》,仅用于本人记录学习笔记,如有侵权请联系删除。
所谓轮询仲裁,就是指每次访问结束后都会更新优先级,举个栗子:假设有N个请求,分别编号为0,1,2,…,N-1,初始时刻,这N个请求的优先级为0>1>2>…>N-1,某个时刻,仲裁器将总线的控制权交给了请求i(0<=i<=N-1),则这之后这N个请求的优先级修改为i+1>i+2>…>N-1>0>1>…>i。
在本文中,我们设计了一个3请求的总线仲裁器,代码如下:
`timescale 1ns/10ps
module bus_arbitor(
input logic clk,
input logic rst_n,
input logic signal_a, //三个主机,轮询仲裁
input logic signal_b,
input logic signal_c,
output logic [1:0] grant);
logic [1:0] last_grant; //记录上一次总线仲裁结果
parameter A = 2'b00; //将总线控制权交给A
parameter B = 2'b01; //总线控制权交给B
parameter C= 2'b10; //总线控制权交给C
parameter NULL = 2'b11; //
always@(posedge clk,negedge rst_n)
if(~rst_n)
begin
grant<=NULL;
last_grant<=NULL;
end
else
begin
case({signal_a,signal_b,signal_c})
3'b000:begin
grant<=NULL;
last_grant<=last_grant;
end
3'b001:begin
grant<=C;
last_grant<=C;
end
3'b010:begin
grant<=B;
last_grant<=B;
end
3'b100:begin
grant<=A;
last_grant<=A;
end
3'b110:begin //A,B同时请求总线,需要进行仲裁
case(last_grant)
A:begin grant<=B;last_grant<=B;end
B:begin grant<=A;last_grant<=A;end
C:begin grant<=A;last_grant<=A;end
NULL:begin grant<=A;last_grant<=A;end
endcase
end
3'b101:begin //A,C同时请求总线
case(last_grant)
A:begin grant<=C;last_grant<=C;end
B:begin grant<=C;last_grant<=C;end
C:begin grant<=A;last_grant<=A;end
NULL:begin grant<=A;last_grant<=A;end
endcase
end
3'b011:begin //B,C同时请求总线
case(last_grant)
A:begin grant<=B;last_grant<=B;end
B:begin grant<=C;last_grant<=C;end
C:begin grant<=B;last_grant<=B;end
NULL:begin grant<=B;last_grant<=B;end
endcase
end
3'b111:begin //三个总线同时请求
case(last_grant)
A:begin grant<=B;last_grant<=B;end
B:begin grant<=C;last_grant<=C;end
C:begin grant<=A;last_grant<=A;end
NULL:begin grant<=A;last_grant<=A;end
endcase
end
default:begin grant<=NULL;last_grant<=last_grant;end
endcase
end
endmodule
tb代码
`timescale 1ns / 1ps
module sim_tb;
logic clk;
logic rst_n;
logic signal_a;
logic signal_b;
logic signal_c;
logic [1:0] grant;
initial begin
clk=0;
forever begin
#5 clk=~clk;
end
end
//rst_n
initial
begin
rst_n=0;
#100
rst_n=1;
end
//signal_a,b,c
always@(posedge clk,negedge rst_n)
if(~rst_n)
{signal_a,signal_b,signal_c}<=0;
else if($urandom%2==1)
{signal_a,signal_b,signal_c}<=$urandom%8;
else
{signal_a,signal_b,signal_c}<=0;
//inst
bus_arbitor U(.*);
// input logic clk,
// input logic rst_n,
// input logic signal_a, //三个主机,轮询仲裁
// input logic signal_b,
// input logic signal_c,
// output logic [1:0] grant);
endmodule
可以看到,当A获得请求后,优先级顺序变为BCA,B获得请求后,优先级顺序变为CAB,C获得请求后,优先级顺序变为ABC,若当前无请求,则last_grant信号保持不变(last_grant信号用于保存上一次仲裁器给出的结果,都无请求时仲裁结果不保存)。
优先级固定不变,比如优先级永远都是0>1>2>…>N-1。代码实现:
`timescale 1ns/10ps
module fixed_bus_arbitor(
input logic clk,
input logic rst_n,
input logic signal_a, //三个主机,轮询仲裁
input logic signal_b,
input logic signal_c,
output logic [1:0] grant);
parameter A = 2'b00;
parameter B = 2'b01;
parameter C = 2'b10;
parameter NULL =2'b11;
//
always@(posedge clk,negedge rst_n)
if(~rst_n)
grant<=NULL;
else
begin
casez({signal_a,signal_b,signal_c}) //优先级A>B>C
3'b1zz:grant<=A;
3'bz1z:grant<=B;
3'bzz1:grant<=C;
default:grant<=NULL;
endcase
end
endmodule