【芯片前端】与RR调度的相爱相杀——verilog实现RR调度器2

前言

【芯片前端】与RR调度的相爱相杀——verilog实现RR调度器1

上篇博客把一个基本的RR调度器实现了下,然后这篇来处理其中存在的keep问题;

keep问题

目前已经实现的代码能够实现基本的rr调度,但是在调度时候会遇到两个问题:

1.由于grant是实时由new_grant和old_grant逻辑生成的,有可能导致grant的值在两次ack之间发生改变,由于grant一般直接作用于对外输出valid以及info选取,这会导致valid维持有效期间info信息改变,而在一些协议如axi中valid置起后至握手前,info信息是不允许改变的,也就是说目前的RTL实现可能会违背一些接口协议;

 如上图,bit[1]本身已经得到调度,但是在ack之前bit[0]为高有效了这就使得grant值改变,调度出的info也会随之改变了;

2.还是因为grant会在ack回来之前会有跳变,这可能会导致低优先级区域(即power为0对应的bit)的请求难以得到调度,举个例子:

req = 'b0011, req_after_power = 'b0010 => mask = 'b1100 => grant = 'b0010

下一拍power = 'b0011, req = 'b0001, req_after_power = 'b0000,那么按照算法需要掉bit[0],因此grant = 'b0001;在很长一段时间内没有回ack,此时req[3]为高有效了,那么按照此时的rtl实现,req_after_power = 'b1000,那么grant会跳变为'b1000,本来应该得到调度的bit[0]没有被调度出去,而出去的是后来的bit[3];

keep问题的解决

keep问题的解决思路就是,在等待ack返回之前,不能改变req的值;在没有等待ack的时候,req的值可以进入调度:

generate
    if(KEEP_MODE == 1)begin: KEEP_MODE_PATH
        reg keep;
        reg [WD -1:0]req_old;
        always @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                keep    <= 1'b0;
                req_old <= {WD{1'b0}};
            end
            else if(ack)begin
                keep <= 1'b0;
            end
            else if((|req) && (~keep))begin
                keep    <= 1'b1;
                req_old <= req;
            end
        end
        assign req_real = keep ? req_old : req;
    end
    else begin: NO_KEEP_MODE_PATH
        assign req_real = req;
    end
endgenerate

通过一个参数KEEP_MODE,来进行keep模式的处理,之后以req_real作为调度输入进行rr调度,因此在grant起ack没回之前,req_real不能够改变,看波形:

 不过即使这样处理了,这个模块还是有一个坑在里面。

RTL代码

module rr_dispatch #(parameter WD = 2, KEEP_MODE = 1)
(
	input clk,
	input rst_n,
	input [WD -1:0] req,	
	input ack,
	
	output [WD -1:0] grant
);

wire [WD -1:0] req_real;

generate
    if(KEEP_MODE == 1)begin: KEEP_MODE_PATH
        reg keep;
        reg [WD -1:0]req_old;
        always @(posedge clk or negedge rst_n)begin
            if(~rst_n)begin
                keep    <= 1'b0;
                req_old <= {WD{1'b0}};
            end
            else if(ack)begin
                keep <= 1'b0;
            end
            else if((|req) && (~keep))begin
                keep    <= 1'b1;
                req_old <= req;
            end
        end
        assign req_real = keep ? req_old : req;
    end
    else begin: NO_KEEP_MODE_PATH
        assign req_real = req;
    end
endgenerate

reg  [WD -1:0] req_power;
wire [WD -1:0] req_after_power = req_real & req_power;

wire [WD -1:0] old_mask = {req_after_power[WD -2:0] | old_mask[WD -2:0], 1'b0};
wire [WD -1:0] new_mask = {req_real[WD -2:0]        | new_mask[WD -2:0], 1'b0};

wire old_grant_work = (|req_after_power);

wire [WD -1:0] old_grant = ~old_mask & req_after_power;
wire [WD -1:0] new_grant = ~new_mask & req_real;

always @(posedge clk or negedge rst_n)begin
	if(~rst_n)begin
		req_power <= {WD{1'b1}};
	end
	else if(ack) begin
		if(old_grant_work)begin
			req_power <= old_mask;
		end
		else if(|req)begin
			req_power <= new_mask;
		end
	end
end

assign grant = old_grant_work ? old_grant : new_grant;

endmodule

你可能感兴趣的:(芯片前端设计,前端)