RR调度的应用与方案

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

注:本文由作者授权转发,如需转载请联系作者本人

在FPGA的设计里,RR(Round-Robin)调度是一个非常重要的话题。所谓RR调度就是从多个队列中公平地选一个队列进行处理。可以用在多种不同的场景中。

1、分发场景
如下图所示,在多引擎的场景中,假定有源源不断的任务需要分发到4个后续引擎中去处理。那么这个分发逻辑就是一个调度系统,调度的方式有很多,比如最简单的逐个引擎分发,但是要达到“快和公平”这2个条件,那首当其冲选择RR调度了。

一是按顺序哪个引擎空闲就给哪个引擎任务,遇到忙碌的引擎需要跳过,直接判断下一个引擎,直到有空闲的引擎。示意代码如下图所示,这个方案在4个队列的场景下是完全可行的,但是当引擎多了以后,比如32个引擎,采用这种写法就会有2个问题了,第一就是组合逻辑可能较大,第二就是引擎多了,在一个always里写的代码量就巨大了。

always@(posedge clk_sys or posedge rst)
begin
if(rst == 1'b1) begin
rr_state <= IDLE;
end
else begin
case(rr_state)
IDLE: begin
if(q0_req == 1'b1) begin
rr_state <= Q0_RR;
end
else if(q1_req == 1'b1) begin
rr_state <= Q1_RR;
end
else if(q2_req == 1'b1) begin
rr_state <= Q2_RR;
end
else if(q3_req == 1'b1) begin
rr_state <= Q3_RR;
end
else;
end
Q0_RR: begin
if((q1_req == 1'b1) && (q0_done == 1'b1)) begin
rr_state <= Q1_RR;
end
……
else;
end
……
default;
endcase
end
end

2、命令和数据同时调度场景
这种场景是多个队列合并成一个队列,但是每个队列包含的是2个通道,数据通道和命令通道,如下图所示,用的比较多的场景就是多个用户同时访问DDR。在该场景中有一个前提,那就是:一个cmd一般是单cycle数据,一次data是多cycle数据。这种场景下的调度,可以有2种方案。

方案一:cnt轮询,当4个通道中有一个通道有请求的时候,cnt在0到3之间不断地翻转计数,记到多少,就判断该队列是否有请求,如果有请求,就读出cmd,并写入到后级FIFO中缓存,然后从FIFO中读出命令,并从该命令对应的队列中读取data。

该方案最大的好处就是简单。一个cnt解决调度问题,但是也有一些缺点,或者说应用限制。就是每个队列data的cycle数 >= 通道数,因为该方案中每个队列的轮询需要4个cycle,如果数据太短,小于4个cycle的话,数据的调度就会出现气泡,影响性能,尤其是当队列数较多的时候。

方案二,要解决方案一中的缺点,就可以采用第一个分发场景中提及的方案。每一次的轮询只需要一个cycle获得结果,相比方案一需要4个cycle,在小包场景下,优势明显。

3、数据调度场景
该场景和上述场景2相比就是少了每个队列的命令通道,只有数据,这种场景的调度和场景1类似,是场景1的反向操作。和场景2相比,少了cmd通道,因此无法使用cnt轮询的方案。它的实现方案和场景1是类似的,也有一些不同的点。

比如当4个队列都有数据的时候,调度后的输出是否是背靠背的?即调度的性能是否达到线速,这就需要结合实际需求,采用一些调度的技巧了。

调度是逻辑设计中一个非常重要的功能,不管业务如何复杂,基本都可以分解成上述几种情况。当队列少的时候,都可以用上述的方案实现高效调度,假如在队列很多的时候呢?下一篇我们介绍RR调度的通用实现方式。

最新文章

最新文章