round robin轮询仲裁器
上一节描述了固定仲裁器的设计,固定仲裁器的逻辑简单,实现也比较容易,但是固定仲裁器有个问题:固定仲裁器各请求的优先级是不会发生变化的。那么就会存在有请求一直拿不到权限被饿死的场景。
为了解决这个问题,提出了RR 仲裁器, RR仲裁器会在每一次请求被taken之后,将当前请求的优先级调整为最低,从而达到仲裁的公平性。
1. 思路1
最简单的思路就是在master不多时,根据上一次的grant来对req进行移位,得到req_shift,之后采用固定优先级仲裁器直接执行得到新的grant_shift,之后再复位回去,得到最终的grant;
2. 思路2
在讲固定优先级仲裁器时,最后有提到采用req-1 取反来找第一个1的时候,这个思路是可以扩展的,采用req - onehot_a 是可以找到以onehot_a为开始的第一个1,此时就可以得到:
grant = req & ~(req-onehot_a);
这里会有个问题:onehot_a是可能比req大的,从因此这里扩展req来解决这个问题
grant_ext = {req, req} & ~({req,req}-onehot_a)
grant_ext = grant_h | grant_l;
当我们有了这个基础之后,那么就可以实现对应的功能了。
a. 获取onehot_a: 按照RR的概念,onehot_a可以通过grant左移一位来表示,注意grant代表的是当前选择的req,在下一轮的仲裁中它的下一个bit才是优先级最高的bit,因此这个需要左移grant;
always @(posedge clk) beginif(!rstn) onthot_a <= {{NUM_REQ-1{1'b0}}, 1'b1};elseif(|req)onehot_a <= {grant[NUM_REQ-2:0, grant[NUM_REQ-1]}; end
这个思路和前一个思路的缺点一样,就是看着功能是实现了,但是timing和面积在req较多时比较差。现在基本上的实现都是采用mask的方式来实现,也就是下面介绍的思路3
3. 思路3
思路2本质上是没有动req,想通过调整优先级的方式来实现仲裁。而与之对应就是,优先级不变,对req进行处理来完成对应的操作。
在RR 仲裁中的实现思路目前看起来都是采用掩码 mask的方式来实现,将已经给过grant的req 位mask掉,得到mask req,再将mask req放入固定优先级仲裁器中选择,得到mask grant,轮询一周后,mask grant变为0, 采用新的req从新开始。
那么,怎么找mask呢?
我们先看mask的特征吧,mask的目的是将比当前选择请求的优先级低的所有请求都保留下来,
req[3:0] = 4'b0010
pre_req[3:0] = 4'b1100pre_req[0] = 0;
per_req[1] = req[0] | pre_req[0];
...
pre_req[n-1] = req[n-2] | pre_req[n-2]so
pre_req[n-1:1] = req[n-2:0] | pre_req[n-2:0]
知道了怎么获得mask,下面就看怎么更新mask吧:
1,默认情况下, mask为all 1,都可以放进来请求;
2. 当req_mask有效时,更新mask为前一次的mask侧请求的mask;
3. 当req_mask无效时,但是req有效时,更新mask为当前这一轮unmask侧的mask;
4. 都无效,mask保持不变
// mask updatealways @ (posedge clk) beginif (rst) beginmask_q <= {N{1'b1}};end else beginif (|req_mask) beginmask_q <= pre_mask;end else beginif (|req) begin mask_q <= pre_unmask;end else beginmask_q <= mask_q ;endendendend
再看完mask的产生和更新逻辑之后,看看怎么利用mask 实现RR吧!
1. MASK 侧
根据上述pre_req的逻辑, 这里pre_req为mask, 这里的req也应该是mask之后的req,因此,这里伪代码变为:
表示当req mask有效时,将当前最新的mask更新到mask_q中;
req_mask = req & mask_q;
pre_mask[n-1:1] = req_mask[n-2:0] & pre_mask[n-2:0]grant_mask = req & ~ pre_mask;
2. UNMASK侧
pre_unmask[n-1:1] = req[n-2:0] & pre_unmask[n-2:0]
pre_unmask[0] = 1'b0;grant_unmask = req & ~ pre_unmask;
3. Grant
最后根据 req_mask选择grant 即可。