基于掩码的轮询调度方案以应用场景

本文转载自: FPGA的现今未微信公众号

在FPGA的设计中,调度是一个不可避免的话题。去年的时候写过一篇文章,介绍了调度的常用方案和应用场景,这种方案有一个特点就是需要先对数据进行缓存,然后开始对数据进行调度,并根据各个队列的调度请求以及当前的调度状态来确定下一个调度的端口。这种方案在队列少的时候,相对比较简单,但是消耗缓存。

这里介绍一种新的公平调度方案,和前面的方案相比,最大的特点是不缓存数据,根据每个队列的调度申请,做出仲裁结论,各个队列根据仲裁结论再主动发送数据给调度模块。即调度模块本身不缓存数据,仅做仲裁。尤其是当队列很多的时候,比如32个队列,如果采用前面介绍的缓存方案,一般采用多级缓存调度,否则代码会非常复杂。本文介绍的调度方案就比较合适这种多队列调度的场景。

算法实现

网上有很多关于这种算法实现的方案,这里选择一种比较简单的方案做一个搬运总结。调度仲裁算法的核心的思想,就是记录上一次调度的结果,然后通过掩码的方式,获取下一次调度的结果。要实现这种算法,需要先了解几个变量:
1、last_grant:锁存地上一次的响应结果;
2、req_mask:根据上一次的响应结果,获取mask,即屏蔽上一次已经响应过的队列,req_mask = (last_grant[2:0],last_grant[3]) - 1;
3、~req_mask:对req_mask按位取反;
4、mask_result:请求与掩码运算后的最终结果。req&(~req_mask)如果不等于0,mask_result就取该值,否则取req&req_mask的值;
5、grant:独热码表示的调度结果,mask_result & (~mask_result + 1)

这几个变量不知道是什么意思不要紧,我们通过一个具体的例子来说明该算法是如何通过上述变量来实现调度的。

通过上表我们可以看出,~req_mask掩掉上一次响应队列以及低位的队列(默认低位的队列是已经调度过)。将请求信号和掩码做“&”运算后,就得到了掩码后的请求,也就是掩码结果,然后寻找最低位的1,即得到响应。当然如果响应为1000的时候,掩码需要做一些特殊处理,因为上一次响应的是最高位的队列,接下来就不应该掩掉任何一个队列了。

应用案例1——N到1的调度

N到1的调度,即多个队列的数据向一个出口发送,由于这种调度方案不再对数据进行缓存,仅仅是做一个仲裁控制逻辑。因此在实际应用中,主要是包括2个部分,如下图所示:

第一部分就是上述的调度逻辑rr_arbit,第二就是数据选择,当rr_arbit给出调度结果后,对应的数据通道打开,由用户主动把数据从输入口发过来,然后再将数据输出口发送出去。数据发送完毕后,再开始第二轮的调度,以此类推。

应用案例2——1到N的分发

那还有一种场景是1到N数据分发,即把输入的数据,按照请求,公平地分发给多个队列。究竟发送给哪个队列?通过上述的仲裁方案,找到下一次需要发送的队列。如下图所示:

可以接受数据的队列先发送req请求,仲裁逻辑根据请求得到仲裁结果,然后把数据分发给仲裁得到的队列。当一帧数据发送完成后,开始下一轮的调度,以此类推。

总结

最新文章

最新文章