一、概述
RR(Round Robin)为轮询调度器,该类型的调度器与上一章节的SP调度器的实现原理有些相似,但是RR调度的功能与SP调度相差较大,RR调度器主要解决在调度过程中多个请求调度源的公平性问题,相较于SP调度,RR调度器通过轮询各请求源判断请求源的访问情况,当某一请求源被成功调度后,该请求源在下一拍的调度信用降至最低,而此时请求源的左边的信用度增至最高,所以RR调度可以解决调度的公平性问题,常用于多个 通道同时申请调度,在数字芯片设计过程中经常使用。
二、实现重点
RR调度实现的原理前面已经说了一部分,而实现RR调度小编认为有几个地方需要注意:
1、记录当前调度指针的位置,该指针的右边的调度源在下一次调度的时候需要被屏蔽;
2、当调度请求源有效时,通过计算得到需要屏蔽的调度源,并找到左右两侧的首1(与SP相似);
三、RR调度器的Verilog代码
话不多说,直接上verilog代码:
module RR_SH#(
parameter SH_NUM = 8 // RR调度器的请求端口数量
)(
input clk ,
input rst_n ,
input [SH_NUM - 1 : 0] sh_req , //调度源
input sh_en , //调度使能,高电平有效,调度器在该信号有效时进行工作
output[SH_NUM - 1 : 0] sh_grant, //调度结果,该接口为独热码输出
output sh_vld //调度结果有效标识,高有效表示调度结果有效
);
wire [SH_NUM - 1 : 0] right_grant ;//调度器右侧调度结果,当调度指针左侧没有访问源时有效
wire [SH_NUM - 1 : 0] rr_req ;//调度使能有效时的调度请求
wire [SH_NUM - 1 : 0] next_mask_ptr ;//当次调度掩码,每一bit代表一个访问源,为0时屏蔽访问源
reg [SH_NUM - 1 : 0] next_mask_ptr_ff1;//记录每次的调度掩码
wire [SH_NUM - 1 : 0] left_req ;//调度指针左侧的调度源,该请求源为屏蔽后的请求源
wire [SH_NUM - 1 : 0] left_grant ;//左侧调度结果
wire [SH_NUM - 1 : 0] right_mask ;//右侧调度掩码
wire [SH_NUM - 1 : 0] left_mask ;//左侧调度掩码
assign sh_vld = sh_en == 1'b1 ? |sh_req : 1'b0 ;
assign rr_req = sh_en == 1'b0 ? {SH_NUM{1'b0}} : sh_req;
assign left_req = (next_mask_ptr_ff1) & rr_req ;
assign right_grant = rr_req & (~(rr_req - 1'b1)) ;//找首1
assign left_grant = left_req & (~(left_req - 1'b1)) ;//找首1
assign right_mask[0] = 1'b0 ;
assign left_mask[0] = 1'b0 ;
genvar i;
generate
for(i=1;i<SH_NUM;i=i+1)begin:MASK_GEN
assign right_mask[i] = |rr_req[i-1:0] ;
assign left_mask[i] = |left_req[i-1:0];
end
endgenerate
assign sh_grant = left_req == {SH_NUM{1'b0}} ? right_grant : left_grant;
assign next_mask_ptr = left_req == {SH_NUM{1'b0}} ? right_mask : left_mask ;
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)
next_mask_ptr_ff1 <= {SH_NUM{1'b0}};
else if(sh_vld == 1'b1)
next_mask_ptr_ff1 <= next_mask_ptr;
else ;
end
endmodule
四、实现说明与约束
1、由于上述代码可以实现在调度源有效的当拍出调度结果,该电路实现的过程中使用组合逻辑实现,所以端口数量不能设置过大,一般小于128,否则对时序压力、后端实现的压力较大。
2、调度器最开始从LSB开始轮询。
五、RR调度器仿真结果示意图
小编是使用vivado TCL进行仿真,TCL脚本放在下方了,当然也可以自己编写TB进行仿真哦
add_force {/test/clk} -radix hex {1 0ns} {0 5000ps} -repeat_every 10000ps
add_force {/test/rst_n} -radix hex {0 0ns}
run 100 ns
add_force {/test/sh_req} -radix hex {0 0ns}
add_force {/test/sh_en} -radix hex {0 0ns}
run 40 ns
add_force {/test/rst_n} -radix hex {1 0ns}
run 30 ns
add_force {/test/sh_req} -radix hex {1 0ns}
add_force {/test/sh_en} -radix hex {1 0ns}
run 10 ns
add_force {/test/sh_req} -radix hex {2 0ns}
run 10 ns
add_force {/test/sh_req} -radix hex {3 0ns}
run 10 ns
add_force {/test/sh_req} -radix hex {4 0ns}
run 10 ns
add_force {/test/sh_req} -radix hex {5 0ns}
run 10 ns
run 10 ns
add_force {/test/sh_req} -radix hex {6 0ns}
run 10 ns
add_force {/test/sh_en} -radix hex {0 0ns}
run 50 ns
add_force {/test/sh_req} -radix hex {7 0ns}
run 10 ns
add_force {/test/sh_en} -radix hex {1 0ns}
run 10 ns