01仲裁机制
提出占用资源的模块需要产生一个访问请求request,所有的请求输入仲裁器之后,仲裁器需要根据仲裁算法,返回一个grant来响应某一模块的请求。
仲裁器只能让一个模块得到许可,因为资源(总线)同一时刻只能由一个模块占用。
常见的仲裁机制有以下三种:
- 固定优先级仲裁器Fixed Priority Arbiter
- 轮询仲裁器Round Robin Arbiter
- 伪随机仲裁器Pseudo Random Arbiter
固定优先级: 即事先确定好各个模块的访问优先级,当多个请求发起时,按照优先级从高到低来给出许可,某些情况下,部分请求的优先级必须高于其它请求(比如车控系统中的刹车请求),这时就要采用固定优先级的仲裁算法;
轮询: 当某次请求被许可之后,则下一个优先级的请求会被置成最高,若下一次需要仲裁的请求中没有最高优先级对应的请求,则维持优先级顺序(按照基础优先级顺序执行本轮仲裁),直到最高优先级请求被响应。
例如:初始优先级从高到低1-2-3,现在来了一波请求序列123-13-23-123-13,那么每轮分别是哪个请求被许可?
答:每轮最高优先级 1-2-2-3-1,被响应许可的顺序 1-1-2-3-1
*也有一种轮询机制是优先级反转的,一个请求被响应许可之后,它的优先级就降到最低。
伪随机: 通过伪随机算法随机赋予请求优先级。
02算法实现
1、Fixed Arbiter
设 req_i [3:0], 由于是固定优先级,可以事先约定:低位优先级高,高位优先级低
(注意仲裁器的输入端口已经确定好优先级,因此外部请求信号连接时应根据仲裁器规定的优先级顺序按需求连接)
在这个前提下,仲裁的本质其实就是从低位到高位寻找第一个“1”
那么有没有什么逻辑操作可以快速定位一个序列中从低到高的第一个“1”呢?
显然,减1操作就符合这个需求。在二进制的减1操作中,低位如果是0,就会向前借位,结果是1,直到借位的那一位是1,结果才得0,因此只需要根据结果从低到高的第一个0在哪一位就能确定哪一位该被许可响应。
假设这次请求req_i = 4'b1010,即第二和第四个设备发起了请求,那么req_i-1 = 4’b1001,可以从低到高的第一个0位于第二位,也就是req_i[1]对应的请求可以被响应。
那么如何将这个算法用简单的逻辑实现呢,用序列检测的方法去遍历req_i-1的结果显然过于复杂且耗时,会大大拖累性能。最好能用一个简单的组合逻辑就把这个0所在的位找出来。
可以观察到,对req_i-1的结果按位取反后,得到~(req_i-1)= 4‘b0110,与req_i只有一位相同,且那一位就是被响应许可的位。于是gnt [3:0]的逻辑就呼之欲出了:
gnt_o = req_i & ~(req_i-1);
其实也很好理解,减1操作,相当于对参与运算的低两位10进行了取反,对于被减数来说,前两位10其实并没有变化,直接落到结果对应的位上,所以对结果进行取反得到0110,再和被减数本身按位与,得到的结果是0010,直接筛选出了被借位的那个“1”
2、Round Robin Arbiter
有了固定优先级仲裁器的珠玉在前,轮询仲裁器的算法自然就跃然纸上。既然核心思想就是通过减1操作来找出需要被响应的请求,那么已经响应过的请求直接让它不参与减1计算即可。被减数是外部输入的req_i,是不能动的,但是减数是可以操作的,假如req_i[0]的请求刚被响应过,那么只需要让减数的1左移一位得到0010,就相当于让最低位不参与计算,那么按照轮询规则,下一个被响应的请求就是req_i[1]
但凡事皆有例外,固定优先级的减1操作可以保证一定能检索到优先级最高的那个请求(只要req_i不是全0),但是轮询算法因为减数的移位会把低位排除计算,可能出现没被排除计算的请求位没有1,而被排除的请求位有1的情况,如下图所示,此时根据我们的算法得到的结果是0000,低两位的设备发起了请求,但是仲裁器却没有输出,出现了功能错误。
这是由于我们没有将被排除计算的低位请求加入循环移位的仲裁机制中,如果高位均没有发起请求,仲裁器还是需要按照约定的优先级顺序给低位的请求发起响应。
根据这个思路,自然就能想到:当高位没有发起请求,而低位有请求时,按照固定优先级顺序算法再计算一次。但是问题又来了,引入新的逻辑来判断gnt_o的输出以及再进行一次仲裁又会拖慢响应速度,最好有个一步到位的算法,能同时解决两种情况下的轮询仲裁。
回归到优先级算法的本质,上图中 gnt_o输出全0的原因是向上借位溢出,向上借位的本质又是高几位进行减1操作,那么让req_i变成我们需要借位的那个“高几位”不就行了吗?
如图,将req_i和gnt_o进行double拓宽,这样就能兼顾高位有无请求两种情况了。最后一步,就是将double过的gnt_o再变回原来的位宽。根据算法,double_gnt_o要么高四位有效,要么低四位有效,而且是独热的(One-hot),因此只需要将前四位与后四位进行按位或操作就可以得到正确的gnt_o
assign double_reqs = {2{reqs_i}};
assign double_gnts = ~(double_reqs - priority_flag) & double_reqs;
assign gnts_o = double_gnts[2*REQ_NUM:REQ_NUM] | double_gnts[REQ_NUM-1:0];
3、Pseudo random Arbiter
随机仲裁器其实就很好实现了,每次有请求到来时,让减数中独热的那一位出现在随机的位置上,就实现了优先级的随机生成。本文不再赘述。
-
算法
+关注
关注
23文章
4608浏览量
92847 -
信号
+关注
关注
11文章
2790浏览量
76736 -
仲裁器
+关注
关注
0文章
12浏览量
6640
发布评论请先 登录
相关推荐
评论