RTL编码之轮询调度方法

在RTL编码中,经常遇到多个队列(或者多通道/FIFO)轮询(round-robin)调度。

若队列(或者通道/FIFO)数较少,可以通过case语句实现轮询调度。

方法1:使用case语句实现round-robin调度器。

module rr_sch (
    input                               clk         ,
    input                               rst_n       ,
    input                               sch_en      , // 调度使能,单拍有效
    input           [4-1:0]             que_st      , // 队列的状态
    output  reg     [2-1:0]             que_id        // 当前选中的队列
);

always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0) begin
        que_id <= 3'd0;
    end
    else if ((sch_en == 1'b1) && (|que_st == 1'b1)) begin
        case (que_id)
            2'd0: que_id <= (que_st[1]) ? 2'd1 :
                            (que_st[2]) ? 2'd2 :
                            (que_st[3]) ? 2'd3 : 2'd0;
            2'd1: que_id <= (que_st[2]) ? 2'd2 :
                            (que_st[3]) ? 2'd3 :
                            (que_st[0]) ? 2'd0 : 2'd1;
            2'd2: que_id <= (que_st[3]) ? 2'd3 :
                            (que_st[0]) ? 2'd0 :
                            (que_st[1]) ? 2'd1 : 2'd2;
            default: que_id <= (que_st[0]) ? 2'd0 :
                            (que_st[1]) ? 2'd1 :
                            (que_st[2]) ? 2'd2 : 2'd3;
        endcase
    end
    else;
end

endmodule

该调度器根据输入的队列状态和上一次队列索引,选择下一次调度的队列索引。
缺点:不易扩展,当队列数量增加时,case语句会变得很长。

方法2:使用for循环实现round-robin调度器。

module rr_sch #(
    parameter NUM = 4   ,
    parameter WIDTH = $clog2(NUM)
)(
    input                               clk         ,
    input                               rst_n       ,
    input                               sch_en      ,
    input           [NUM-1:0]           que_st      ,
    output  reg     [WIDTH-1:0]         que_id
);

reg     [WIDTH-1:0]     rr_id;

always @ (posedge clk or negedge rst_n) begin : RR_SCH
    integer i;
    if (rst_n == 1'b0) begin
        que_id <= {WIDTH{1'b1}};
    end
    else if ((sch_en == 1'b1) && (|que_st == 1'b1)) begin
        for (i = NUM; i >= 1; i = i - 1) begin // 遍历所有队列的状态
            rr_id = que_id + i;
            if (que_st[rr_id] == 1'b1) begin
                que_id <= rr_id[WIDTH-1:0];
            end
        end
    end
    else;
end

endmodule

该调度器根据输入的队列状态和上一次队列索引,从索引+1的位置开始遍历队列,直到当前索引。等同于case语句实现的方法。

举例说明,假如上一次队列索引是4,队列状态que_st = 8'b1111_1111,循环过程如下图。

循环遍历顺序,由4->3->2->1->0->7->6->5结束,只要对应状态位是1,始终由后面索引覆盖。也就是最后遍历的在本次优先级最高,或者说上一次队列索引+1在本次优先级最高,完全等同于case语句实现的方法。

缺点:NUM大的情况下,时序可能不满足。

优点:相比较case语句实现的方法,可参数化扩展。

方法3:使用for循环实现round-robin调度器。

module rr_sch  #(
    parameter NUM = 4   ,
    parameter WIDTH = $clog2(NUM)
)(
    input                               clk         ,
    input                               rst_n       ,
    input                               sch_en      , // 调度使能,单拍有效
    input           [NUM-1:0]           que_st      , // 队列的状态
    output  reg     [WIDTH-1:0]         que_id        // 当前选中的队列
);

reg                         que_lsel_vld;
reg     [WIDTH-1:0]         lsel_que;
reg     [WIDTH-1:0]         hsel_que;
wire    [WIDTH-1:0]         que_sel;

always @ ( * ) begin : RR_SCH
    integer i;
    que_lsel_vld = 1'b0;
    lsel_que = {WIDTH{1'b0}};
    hsel_que = {WIDTH{1'b0}};
    if ((sch_en == 1'b1) && (|que_st == 1'b1)) begin
        for (i = 0; i < NUM; i = i + 1) begin
            if (que_st[i] == 1'b1) begin
                if (i < que_id) begin
                    que_lsel_vld = 1'b1; // 前半组选择有效标记
                    lsel_que = i[WIDTH-1:0]; // 前半组选择端口
                end
                else begin
                    hsel_que = i[WIDTH-1:0]; // 后半组选择有效标记
                end
            end
        end
    end
end


assign que_sel = (que_lsel_vld == 1'b1) ? lsel_que : hsel_que;

always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0) begin
        que_id <= {WIDTH{1'b0}};
    end
    else if ((sch_en == 1'b1) && (|que_st == 1'b1)) begin
        que_id <= que_sel;
    end
    else;
end

endmodule

前半组组内SP调度,高位优先级高;后半组组内SP调度,高位优先级高;组间根据lsel_vld信号选择队列索引。注意:前后组由索引决定,因此前后组会跟随索引而发生变化。

举例说明,如下图。

步骤1:假如上一次队列索引是3,队列状态时8‘b1111_0111,由于前半组状态有效,前半部分选择索引2,后半部分选择索引7,因此这次轮询选择索引2;

步骤2:假如上一次队列索引是2,队列状态时8‘b1111_0011,由于前半组状态有效,前半部分选择索引1,后半部分选择索引7,因此这次轮询选择索引1;

步骤3:假如上一次队列索引是1,队列状态时8‘b1111_0001,由于前半组状态有效,前半部分选择索引0,后半部分选择索引7,因此这次轮询选择索引0;

步骤4:假如上一次队列索引是1,队列状态时8‘b1111_0000,由于前半组状态无效,前半部分选择索引6,后半部分选择索引0,因此这次轮询选择索引6;

步骤5:假如上一次队列索引是1,队列状态时8‘b0111_0000,由于前半组状态有效,前半部分选择索引6,后半部分选择索引0,因此这次轮询选择索引6;

步骤5:假如上一次队列索引是1,队列状态时8‘b0011_0000,由于前半组状态有效,前半部分选择索引5,后半部分选择索引0,因此这次轮询选择索引5;

后面步骤省略......

若有不正确的地方,欢迎大家指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值