一、概述
WRR(Weighted Round Robin)为带权重的轮询调度,该调度器在RR调度的基础上增加了权重值进行控制,在多个访问源同时发起调度申请时,会根据当前配置的权重值进行预处理,如果当前某一端口的权重值配置为0时,此时调度器不会将该端口视为有效调度端口。经过预处理后的调度请求,发起RR调度请求,当某一调度请求被响应时,对应当前权重值-1,其他权重值保持不变。本设计中的WRR调度在所有有效调度权重值为0时,会重新刷新一轮权重值。WRR调度器主要为了解决流控问题,即对于流量大的访问源,可配置较大的权重值,对于流量小的访问源,可配置较小的权重值,从而达到流量控制效果。该方式在芯片IC中运用得相当广泛,对于芯片设计人员一定需要掌握!
二、实现重点
在实现WRR调度其中,笔者认为有以下几点值得注意:
1、当所有有效调度权重均为0时,需要重新刷新一轮新的权重值
2、当前权重值配置为0的端口,不参与调度
三、WRR调度器得Verilog代码
module WRR_SCH #(
parameter SCH_PORT_NUM = 2,
parameter WEIGHT_WID = 4
)(
input clk ,
input rst_n ,
input wrr_sch_en ,
input [SCH_PORT_NUM-1 : 0] wrr_sch_req ,
input [SCH_PORT_NUM*WEIGHT_WID-1 : 0] wrr_sch_weight ,
output [SCH_PORT_NUM-1 : 0] wrr_sch_grant ,
output wrr_sch_grant_vld
);
wire rr_sch_en;
wire [SCH_PORT_NUM-1 : 0] wrr_req_pro;
wire refresh_weight_en;
wire [SCH_PORT_NUM-1 : 0] rr_sch_req;
wire [SCH_PORT_NUM-1 : 0] rr_sch_grant;
wire rr_sch_grant_vld;
reg [SCH_PORT_NUM-1 : 0] active_req_all_zero;
reg [WEIGHT_WID -1 : 0] weight_current[SCH_PORT_NUM-1:0];
genvar i0;
generate for(i0=0;i0<SCH_PORT_NUM;i0=i0+1)begin:WRR_REQ_PRO
//process current req(stop current schedule when weight is 0 )
assign wrr_req_pro[i0] = wrr_sch_req[i0] == 1'b1 && wrr_sch_weight[i0*WEIGHT_WID+:WEIGHT_WID];
//refresh weight when active req's weight is all 0
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)
weight_current[i0] <= {WEIGHT_WID{1'b0}};
else if(refresh_weight_en == 1'b1)begin
if(wrr_sch_grant_vld == 1'b1 && wrr_sch_grant[i0] == 1'b1)
weight_current[i0] <= wrr_sch_weight[i0*WEIGHT_WID+:WEIGHT_WID] -1'b1;
else
weight_current[i0] <= wrr_sch_weight[i0*WEIGHT_WID+:WEIGHT_WID];
end
else if(wrr_sch_grant_vld == 1'b1 && wrr_sch_grant[i0] == 1'b1)begin
weight_current[i0] <= weight_current[i0] - 1'b1;
end
else ;
end
always @(*)begin
if(wrr_req_pro[i0] == 1'b1 && weight_current[i0] == {SCH_PORT_NUM{1'b0}})
active_req_all_zero[i0] <= 1'b1;
else if(wrr_req_pro[i0] == 1'b0)
active_req_all_zero[i0] <= 1'b1;
else
active_req_all_zero[i0] <=1'b0;
end
assign rr_sch_req[i0] = refresh_weight_en == 1'b1 ? wrr_req_pro[i0] :wrr_req_pro[i0] == 1'b1 && weight_current[i0] != {SCH_PORT_NUM{1'b0}};
end
endgenerate
assign refresh_weight_en = (&active_req_all_zero == 1'b1) && wrr_sch_en;
assign rr_sch_en = wrr_sch_en ;
assign wrr_sch_grant = rr_sch_grant ;
assign wrr_sch_grant_vld = rr_sch_grant_vld;
//instance RR schedule
RR #(
.SH_NUM (SCH_PORT_NUM )
)U_RR(
.clk (clk ),
.rst_n (rst_n ),
.sh_req (rr_sch_req ),
.sh_en (rr_sch_en ),
.sh_grant (rr_sch_grant ),
.sh_vld (rr_sch_grant_vld)
);
endmodule
注意:在本设计得WRR调度器中,使用了上一节讲述过的RR调度器,所以在实际应用时,需要例化一个RR调度器。RR调度器的相关知识点,可详见芯片IC设计(二)--调度器(RR调度)-CSDN博客
四、实现说明
本设计的WRR调度器可实现端口可配、权重值位宽可配置。
五、WRR调度器的仿真结果示意图
本次WRR调度器在vivado平台上进行仿真,在打开simulation界面后,在TCL console窗口输入以下访真代码即可完成仿真。
add_force {/WRR_SCH/clk} -radix hex {1 0ns} {0 5000ps} -repeat_every 10000ps
add_force {/WRR_SCH/rst_n} -radix hex {0 0ns}
add_force {/WRR_SCH/wrr_sch_en} -radix hex {0 0ns}
add_force {/WRR_SCH/wrr_sch_req} -radix hex {0 0ns}
add_force {/WRR_SCH/wrr_sch_weight} -radix hex {0 0ns}
run 1 us
add_force {/WRR_SCH/rst_n} -radix hex {1 0ns}
run 1 us
add_force {/WRR_SCH/wrr_sch_weight} -radix hex {42 0ns}
run 1 us
add_force {/WRR_SCH/wrr_sch_en} -radix hex {1 0ns}
add_force {/WRR_SCH/wrr_sch_req} -radix hex {1 0ns}
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {0 0ns}
run 10 ns
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {1 0ns}
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {0 0ns}
run 10 ns
run 10 ns
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {1 0ns}
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {0 0ns}
run 10 ns
add_force {/WRR_SCH/wrr_sch_req} -radix hex {3 0ns}
add_force {/WRR_SCH/wrr_sch_en} -radix hex {1 0ns}
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {0 0ns}
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {1 0ns}
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {0 0ns}
run 10 ns
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {1 0ns}
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {0 0ns}
run 10 ns
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {1 0ns}
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {0 0ns}
run 10 ns
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {1 0ns}
run 10 ns
add_force {/WRR_SCH/wrr_sch_en} -radix hex {0 0ns}
run 10 ns
run 10 ns
run 10 ns