仲裁
当多个源和用户需要共享同一资源时,需要某种仲裁形式,使得所有用户基于一定的规则或算法得到获取或访问共享资源的机会。
仲裁方案
- 严格优先级轮询
- 根据优先级的差异,用户访问共享资源的机会也不同。
- 低优先级的用户可能时钟无法得到资源。
- 公平轮询
- 公平的对待所有请求。
- 所有用户获得均等的访问机会,不会有用户时钟无法得到资源。
- 权重轮询
- 兼顾了公平性和差异性。
- 在一个轮询周期内,不同权重的用户会得到不同的访问次数。
- 在一个轮询周期内,不同权重的用户会得到不同的访问时间片。
- 混合优先级(高优先级组和低优先级组)
- 组间按照优先级轮询,组内采用公平轮询。
严格优先级轮询
- 在严格优先级轮询方案中,发出请求的用户有固定的优先级。
- 我们假设有8个用户(agent),agent0具有最高优先级,agent7具有最低优先级。
- 在本方案中,优先级高的用户只要保持请求,就会持续得到授权。随着优先级不断降低,用户得到授权的机会也随之下降。该方案可以根据用户的重要新提供不同的服务,但低优先级的用户可能长时间得不到服务。此时可以通过对高优先级用户增加一些请求约束的方法来避免低优先级用户被“饿死”。
公平轮询
- 在公平轮询方案中,所有用户优先级相等,每个用户依次获得授权。
- 一开始,选择用户的顺序可以是任意的,但在一个轮询周期内,所有发出请求的用户都有公平得到授权的机会。以具有4个用户的总线为例,它们全部将请求信号置为有效(高电平)。request0将首先被授权,紧跟着是request1、request2,最后是request.3。当循环完成后,request0才会被重新授权。
- 仲裁器每次仲裁时,依次查看每个用户的请求信号是否有效,如果一个用户的请求无效,那么将按序查看下一个用户。仲裁器会记住上一次被授权的用户,当该用户的操作完成后,仲裁器会按序轮询其他用户是否有请求。
- 一旦某个用户得到了授权,它可以长时间使用总线或占用资源,直到当前数据包传送结束或一个访问过程结束后,仲裁器才会授权其他用户进行操作。这种方案的一个特点是仲裁器没有对用户获得授权后使用总线或访问资源的时间进行约束。该方案适用于基于数据包的协议,例如,以太网交换或PCI交换机,当多个入口的包希望从一个端口输出时,可以采用这种机制。
- 此外还有一种机制,每个用户获得授权后,可以占用资源的时间片长度是受约束的,每个用户可以占用资源的时间不能超过规定的长度。如果一个用户在所分配的时间结束之前完成了操作,仲裁器将轮询后续的用户。如果在分配的时间内用户没有完成操作,则仲裁器收回授权并轮询后续用户。此方案适用于突发操作,每次处理一个突发(一个数据块),此时没有数据包的概念。传统的PCI总线或AMBA、AHB总线采用的就是这种方案。在PC中,仲裁器会给当前获得授权的主机留出一个或多个时钟周期的时间供主机保存当前操作信息,下一次再获得授权时,该主机可以接着传输数据。
公平轮询(仲裁w/o死周期)
- 在前面公平轮询仲裁器的Verilog RTL代码中,每个用户有三个信号:request(请求)、grant(授权)和end access(结束访问)。为了满足定时要求,我们希望grant为寄存器输出的,同时用户的输出数据也是寄存器输出而不是通过组合逻辑输出的。在总线使用时,我们能观察到总线上存在不能进行数据传输的死周期。当传输的数据包较长或每个突发比较长时,其对传输效率影响不大。然而,当数据包很短时,死周期会影响到总线的使用效率。
- 如图所示为没有间隔的公平轮询仲裁波形。下面给出了一些方法,用于减少甚至消除死周期。
design detil
- 当grant信号有效时,该用户的第一个数据已经准备好并且有效输出。原来的方案中,在用户的grant有效后,它在下一个周期输出数据,现在改为当grant采样为高时,在同一个周期就开始输出数据。此时需要用户提前从内部电路中读出第一个数据。采用这种方案时,仲裁器的设计不变,用户部分需要进行修改。
- 第二种方法是增加额外的信号start_access,它和end_access一起使用。一个用户获得总线使用权并开始操作后,仲裁器通过将start_accees置为有效表示开始新的仲裁过程而不是等待end_access信号变高来开始新的仲裁过程,这样就减少了转换期间的死周期。当下一个用户被授权时,当前用户仍在使用总线,此时新用户不能立即使用总线。仲裁器在当前用户完成操作时会给出end_access_outf信号,新的授权用户此后就可以开始操作了。仲裁器在没有用户使用公共资源时,将resource_idle置为1。当resource_idle为1时,获得授权的用户不需要查看end_access_out信号就可以开始数据操作。
权重轮询(WRR)
- 带权重的轮询(Weighted Round Robin,WRR)方案与常规的轮询方案类似,所不同的是不同的用户得到许可的机会存在差异,也就是说,不同的用户权重不同,权重高的用户得到许可的机会更多。
- 权重的分配存在多种方式,这里介绍两种。
-
第一种方法是为每个用户分配一个变量,该变量决定了在一个轮询周期内该用户能够得到许可(被授权)的次数。该变量是可以通过软件编程进行修改的,因此其轮询权重也可以相应调整。
-
例如,有三个用户,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…。
权重轮询(WRR):第二种方法
(1)design detil
下面是采用第二种权重轮询方式的Verilog代码及仿真结果,当所有用户都同时发出请求时,轮询序列为:
两组轮询(混合轮询)
- 在一些应用中,用户被分成两组:快组和慢组。
- 如图所示,快组内的用户具有相同的优先级,内部采用公平轮询方式。类似地,慢组内的用户也具有相同优先级,慢组内部也采用公平轮询方式。快组、慢组之间采用权重轮询方式。
- 例如,快组有两个用户(A,B),慢组也有两个用户(C,D)。如果所有用户都发出请求,那么轮询序列为:
参考《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
仿真测试文件和轮询仲裁所给出的一致,只需修改例化时模块的名字即可,以下是仿真波形: