RTL仲裁器设计

当多个Master访问一个Slave时,该Slave就需要对这几个Master进行仲裁,实际上有很多仲裁算法,此处就作如下讲解。

仲裁器设计(一) – Fixed Priority Arbiter
仲裁器设计(二)-- Round Robin Arbiter
仲裁器设计(三)-- Weighted Round Robin
负载均衡算法–轮询法(Round Robin)


1. Fixed_Priority_Arbiter

这种仲裁算法很简单,这几个Master的优先级是固定的,永远是优先级最高的Master可以访问Slave。

1.1. 参数描述

Signal Direction Width(bits) Description
reqinputREQ_WIDTHMaster请求信号,优先级由0到REQ_WIDTH-1依次递减
grantinputREQ_WIDTH表明被赋予访问权的Master索引,该信号只有1bit为1
Parameter Units Description
REQ_WIDTHbit参与仲裁的Master个数

1.2. 逻辑设计

首先可以发现这是一个组合逻辑,即当前的输出只与当前的输入有关。

涉及的数学关系是,req所有为1的位中最低的那一位就是grant为1的那一位。我们可以用真值表表达这层关系

例如3bit

reqgrant
xx1001
x10010
100100

由此可以直接写出逻辑表达式

grant[0] = req[0];
grant[1] = req[1] && (~req[0]);
grant[2] = req[2] && (~req[1])&& (~req[0])
		 = req[2] && (~(req[1] || req[0]));
grant[3] = req[3] && (~req[2])&& (~req[1])&& (~req[0])
		 = req[3] && (~(req[2]||req[1]||req[0]));
...
grant[i] = req[i] && (~(|req[i-1:0]));

由这个逻辑表达式直接得出代码

module fix_prio_arb#(
	parameter	REQ_WIDTH = 15
	)(
		input	[REQ_WIDTH-1:0]		req,
		output	[REQ_WIDTH-1:0]		grant
	);
genvar i;
generate 
	for(i=0;i<REQ_WIDTH;i=i+1) begin
		if(i==0) 
			assign grant[0] = req[0];
		else
			assign grant[i] = req[i] && (~(|req[i-1:0]));
	end
endgenerate
endmodule

当然还有更简单的解法,你不是req从右向左找到第一个1嘛,那就求req的补码。如果req可以表示为'bxxx...xx100...00,那么其补码就是req_offset='b(!x)(!x)(!x)...(!x)(!x)100...000,再令grant = req&req_offset;即可

1.3. 测试

测试也比较简单,此处直接上图

在这里插入图片描述

2. Round_Robin_Arbiter

优先级固定的弊端就是最高优先级的Master可以永远与这个Slave保持通信,其他Master可能永远都没有机会。

于是就有了这个轮询调度算法,这个算法的意思是当所有Master都请求访问时,Slave轮流赋予访问权力

req == {REQ_WIDTH{1'b1}};永远成立

即所有Master都一直请求对Slave进行访问,那么Slave会在每一拍对这几个Master轮流访问。

即访问权限grant信号变成4’b0001→4’b0010→4’b0100→4’b1000→4’b0001→…

也就等价于访问权重变成3210→2103→1032→0321→3210→…(0权重最大、3最小)

req == {REQ_WIDTH{1'b1}};不永远成立

即req信号不是每拍都全bit为1、不是所有Master都一直要对Slave进行访问。那么访问权重还是上述那个顺序,只不过会根据req的取值,访问权重跳跃取值

在这里插入图片描述

如上图,黑色部分是Master轮流访问,红色部分是因为req非全1而导致的权重跳跃现象。

例如Prio==3210;req==4'b1010;时,根据Prio显然grant[1]被置1,那么下一拍它的权重Prio[1]就要为最低值3,其他bit的权重则按照轮询的顺序依次赋值,即Prio==1032。下面的过程同理。

2.1. 参数描述

Signal Direction Width(bits) Description
rstninput1复位
clkinput1时钟
reqinputREQ_WIDTHMaster请求信号,优先级由0到REQ_WIDTH-1依次递减
grantinputREQ_WIDTH表明被赋予访问权的Master索引,该信号只有1bit为1
Parameter Units Description
REQ_WIDTHbit参与仲裁的Master个数
MAX_PRIO_INITIAL_INDEX 初始状态下,权重最高Master的索引,次高的索引是该值+1,并在0~REQ_WIDTH-1之间回环

2.2. 逻辑设计

这不是典型的状态机嘛,状态就是权重最高的bit,所以状态机的状态个数就是REQ_WIDTH

但由于req的取值不确定可能导致权重跳跃,所以每个状态直接都会可以相互转换,这是麻烦的地方。

在这里插入图片描述

MAX_PRIO_BITx

表示bit x权重最大时的状态,想一想该状态下要干什么事情、以及状态转换条件是什么

根据req输出grant

根据MAX_PRIO_INDEX的描述,bit x权重最高时,bit x+1的权重就是次高,则有:

prio[x]表示bit x的权重那么在MAX_PRIO_BITx状态下一定满足prio[x]>prio[x+1]>...>prio[REQ_WIDTH-1]>prio[0]...>prio[x-1];按照这个顺序,req中全部为1中权重最高的那一位,grant置1

哎,这个与Fixed_Priority_Arbiter的区别在哪?Fixed_Priority_Arbiter的权重顺序是prio[0]>prio[1]>...>prio[REQ_WIDTH-1];,区别只是权重顺序不同,那么权重顺序不同在计算grant上有和区别?

想一下Fixed_Priority_Arbiter中是assign grant = req & (~req + 1'b1);,那么权重顺序发生变化时,对req按位取反不变,只不过加的不是’b1,而是权重最高的那一位加1。而权重最高的那一位加1可能会导致结果溢出,而溢出的那个1应该加在bit 0上。

根据grant作状态转换

上面的那个图已经给出状态转换成啥了,这是基于grant信号进行转换的,那么什么时候进行状态转换呢

从功能的角度来说,应该是输入一个req之后输出grant,但是状态不发生转换,直到req发生变化再发生转换。如下图所示。

根据req和当前cur_state可以得到grant,有了grant就可以计算出下一个状态是什么,那么计算出来就要立即转换到吗?不能,因为到了新状态有会有新的grant,有了新grant又会有再新的状态…这样grant就会反复横跳。

在这里插入图片描述

要想知道req什么时候变化就需要对req进行值变化检测,req_diff为高时表示req已经发生了变化。此时cur_state要发生变化,那变成几呢?

如上图所示,由于grant与req之间是组合逻辑,所以req变化而cur_state未变化会导致grant可能出现中间值(图中grant为4’b0001那一拍),这个值显然是不能作为cur_state变化的参考(如绿线所示),而且也可看作grant变化过程中的噪声。

这下cur_state转换的问题解决了,grant出现中间值如何解决?

注意到这一拍的噪声与req_diff为高是时序对齐的,所以只需令输出grant在req_diff为高时保持原值即可,这样nxt_state可以计算出下一个状态。

如何保持原值呢?很简单,只需在req_diff为高时,在grant组合运算逻辑中将req替换为req_d1即可。

在这里插入图片描述

注意按照上面的时序,req变化与grant变化差一拍!

你以为这就完了?并不是,在实际仿真中,会发生如下的情况

在这里插入图片描述

就是说,刚开始req为0,那么grant也是0,在req发生变化后req_diff拉高,但grant依旧为0,nxt_state根据grant得到的结果也是0,那么下一拍cur_state也是0,都是无效数据。

这一切都源自于req非0,但实际情况下其实没有请求发来是非常正常的,所以此处可以改变req_diff拉高的条件,当req为0时不拉高。

代码

然后开始写代码,需要注意的问题就是系统状态的个数也是REQ_WIDTH,所以如何写localparam?

我的处理方法是,不写localparam,将MAX_PRIO_BITx用位宽为REQ_WIDTH且只有bit x为1的常量表示。

module round_robin_arb#(
	parameter	REQ_WIDTH = 15,
	parameter	MAX_PRIO_INITIAL_INDEX = 7
	)(
		input						clk,
		input						rstn,
		input	[REQ_WIDTH-1:0]		req,
		output	[REQ_WIDTH-1:0]		grant
	);
	
reg		[REQ_WIDTH-1:0]		cur_state;
reg		[REQ_WIDTH-1:0]		nxt_state;
reg		[REQ_WIDTH-1:0]		req_d1;
wire	[REQ_WIDTH-1:0]		inital_state;
wire						req_diff;
reg		[REQ_WIDTH:0]		res1;
wire	[REQ_WIDTH:0]		res2;

assign inital_state = {{(REQ_WIDTH-MAX_PRIO_INITIAL_INDEX-1){1'b0}},1'b1,{MAX_PRIO_INITIAL_INDEX{1'b0}}};

always@(posedge clk or negedge rstn) begin
	if(!rstn)
		req_d1 <= 'd0;
	else 
		req_d1 <= req;
end

assign req_diff = (req != req_d1) && (|req_d1);

always@(posedge clk or negedge rstn) begin
	if(!rstn)
		cur_state <= inital_state;
	else 
		cur_state <= nxt_state;
end

always@(*) begin
	if(!req_diff)
		nxt_state = cur_state;
	else if(grant[REQ_WIDTH-1])
		nxt_state = 'b1;
	else
		nxt_state = grant << 1;
end

assign res2 = res1[REQ_WIDTH] + res1;

assign grant = (!req_diff)?(req & res2):(req_d1 & res2);

always@(*) begin
	if(!req_diff)
		res1 = {1'b0,~req} + {1'b0,cur_state};
	else
		res1 = {1'b0,~req_d1} + {1'b0,cur_state};
end

endmodule

2.3. 测试

先上一个tb

`timescale 1ns/1ps

module arb_tb();

logic clk;
logic rstn;
logic	[7:0]		req;
logic	[7:0]		grant;

initial begin
	clk = 1'b0;
	forever #5 clk = ~clk;
end

initial begin
	rstn = 1'b1;
	#20;
	rstn = 1'b0;
	#20;
	rstn = 1'b1;
end

initial begin
	req = 8'h0;
	#100;
	req = 8'hCD;
	#30;
	req = 8'h02;
	#30;
	req = 8'hA0;
	#30;
	req = 8'hB0;
	#30;
	req = 8'h30;
	#30;
end

round_robin_arb#(
	.REQ_WIDTH					(8),
	.MAX_PRIO_INITIAL_INDEX	 	(3)
	)dut(
		.clk				(clk),
		.rstn				(rstn),
		.req				(req),
		.grant				(grant)
	);

endmodule

波形图如下,可以看出grant的结果符合预期

在这里插入图片描述

在这里插入图片描述

3. Weighted_Round_Robin_Arbiter

3.1. 参数描述

3.2. 逻辑设计

3.3. 测试

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Starry丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值