目录

HDLbits-分支预测器简单实现

【HDLbits–分支预测器简单实现】

以下是分支预测器的简单其实现;

1 timer

实现一个计时器,当load 1’b1时,加载data进去,当load 1’b0时进行倒计时;

https://i-blog.csdnimg.cn/direct/18e81cea549943cda90c8f91f02ff9d9.png


module top_module(
	input clk, 
	input load, 
	input [9:0] data, 
	output tc
);
    //==timer logic
    reg[10 -1:0] timer;
    wire timer_clr;
    
    assign timer_clk = (load==0) && (timer==0);
    always @(posedge clk) begin
        if(load) begin
            timer <= data;
        end else begin
            if(timer_clk) begin
                timer <= 0;
            end else begin
                timer <= timer - 1; 
            end
        end
    end
    
    assign tc = (timer==0);
    

endmodule

2.branche predicitors

实现一个经典的分支预测器,通过其counter权重来实现;

https://i-blog.csdnimg.cn/direct/2c8a0ec65d714dd9be4111c8ce7881a3.png


module top_module(
    input clk,
    input areset,
    input train_valid,
    input train_taken,
    output [1:0] state
);
    localparam SNT = 2'b00;
    localparam WNT = 2'b01;
    localparam WT = 2'b10;
    localparam ST = 2'b11;
    
    reg[2 -1:0] cur_sta;
    reg[2 -1:0] nxt_sta;
    
    //==State transition
    always @(*) begin
        if(areset) begin
            nxt_sta = WNT;
        end else begin
            case(cur_sta)
                SNT: 
                    nxt_sta = (train_valid) ? (train_taken ? WNT: SNT): SNT;
                WNT:nxt_sta = (train_valid) ? (train_taken ? WT : SNT) : WNT;
                WT: nxt_sta = (train_valid) ? (train_taken ? ST : WT)  : WT;
                ST: nxt_sta = (train_valid) ? (train_taken ? ST : WT)  : WNT;
            default : nxt_sta = SNT;
        endcase
            
        end

    end
    
    //==State flop-flop
    always @(posedge clk or posedge areset) begin
        if(areset) begin
           cur_sta <= WNT; 
        end else begin
           cur_sta <= nxt_sta; 
        end
    end
	
    //==State output
    always @(*) begin
        state = cur_sta;
    end
endmodule

3.Branch history shift

https://i-blog.csdnimg.cn/direct/74af2c3859654be78b03433807ef4c41.png

题目理解

第一段:建立一个32bit移位寄存器

第二段:当predict_valid = 1时进行移位,将原寄存器数据向左移移位,predict_taken 填充最低位。

第三段:当train_mispredicted = 1时需要替换移位寄存器内数据并移位,使用train_history替换原本的数据并左移一位,,train_taken填充至最低位

第四段:优先级说明同时出现时train_mispredicted 优先级高

第五段:说明输出predict_history[31:0]是移位前的数据。

第六段:说明复位,异步复位


module top_module(
    input clk,
    input areset,

    input predict_valid,
    input predict_taken,
    output [31:0] predict_history,

    input train_mispredicted,
    input train_taken,
    input [31:0] train_history
);
    reg [32 -1:0] shift_reg;
    always @(posedge clk or posedge areset) begin
        if(areset) begin
           shift_reg <= 0; 
        end else begin
            if(train_mispredicted) begin
                shift_reg <= {train_history[30:0],train_taken};
            end else if(predict_valid) begin
                shift_reg <= {shift_reg[30:0],predict_taken};
            end else begin
               shift_reg <= shift_reg; 
            end
        end
    end

    assign predict_history = shift_reg;
    
endmodule

4.Branch direction predictor

构建一个具有 7 位和 7 位全局历史的 gshare 分支预测器,经过哈希处理(使用 xor)到 7 位索引。此索引访问一个包含 128 个条目的 2 位饱和计数器表(类似于pcCS450/counter_2bc).分支预测器应包含一个 7 位全局分支历史寄存器(类似于CS450/history_shift).

分支预测器有两组接口:一组用于执行预测,另一组用于执行训练。预测接口在处理器的 Fetch 阶段使用,用于请求分支预测器对正在获取的指令进行分支方向预测。一旦这些分支沿着管道进行并被执行,分支的真正结果就变得已知了。然后,使用实际的分支方向结果对分支预测器进行训练。

当请求对给定的分支预测 ( = 1) 时,分支预测器会生成预测的分支方向和用于进行预测的分支历史寄存器的状态。然后,更新预测分支的分支历史寄存器(在下一个正时钟边沿)。predict_validpc

当请求对分支进行训练 ( = 1) 时,将告知分支预测器正在训练的分支的分支历史记录寄存器值,以及实际分支结果以及分支是否为误预测(需要管道刷新)。更新模式历史记录表 (PHT) 以训练分支预测器,以便下次更准确地预测此分支。此外,如果被训练的分支被误判,也要在误预测的分支完成执行后立即将分支历史寄存器恢复到该状态。train_validpc

如果错误预测和预测(针对不同的、较年轻的指令)的训练发生在同一周期中,则这两个操作都将希望修改分支历史寄存器。发生这种情况时,训练优先,因为无论如何,被预测的分支都会被丢弃。如果同一 PHT 条目的训练和预测同时发生,则预测会在训练之前看到 PHT 状态,因为训练只会修改下一个正时钟边沿的 PHT。以下时序图显示了同时训练和预测 PHT 进入 0 时的时序。 第 4 周期的训练请求改变了第 5 周期的 PHT 入口状态,但第 4 周期的预测请求输出了第 4 周期的 PHT 状态,而没有考虑第 4 周期中训练请求的影响。

同时使用 PHT 条目 0 进行训练和预测123456789时钟train_validtrain_pc ^ train_history0train_takenPHT[0]123predict_validpredict_pc ^ predict_history0predict_taken火车预测一个bc

https://i-blog.csdnimg.cn/direct/375909eb105842fca58788f67428d5fa.png


module top_module(
    input clk,
    input areset,

    input  predict_valid,
    input  [6:0] predict_pc,
    output predict_taken,
    output [6:0] predict_history,

    input train_valid,
    input train_taken,
    input train_mispredicted,
    input [6:0] train_history,
    input [6:0] train_pc
);
    //11 taken 10 weak-taken 01 weak-not-taken 00 not-taken
    reg pht1[127:0];//taken
    reg pht0[127:0];//w-taken
    wire [6:0]ad,ad2;

 	assign ad=train_history^train_pc;
 	assign ad2=predict_history^predict_pc;
    integer i;
    always@(posedge clk or posedge areset)
        if(areset)
            for (i=0; i<128; i=i+1) begin 
                pht1[i] <= 1'b0; 
                pht0[i] <= 1'b1; 
            end
    	else if(train_valid & train_taken)begin
        	if({pht1[ad],pht0[ad]}==2'b11)
            	{pht1[ad],pht0[ad]}<=2'b11;
        	else
        		{pht1[ad],pht0[ad]}<={pht1[ad],pht0[ad]}+2'b1;  //拿了很多次
   	 	end
    	else if(train_valid & ~train_taken)begin
        	if({pht1[ad],pht0[ad]}==0)
        		{pht1[ad],pht0[ad]}<=0;
        	else
            	{pht1[ad],pht0[ad]}<={pht1[ad],pht0[ad]}-2'b1;  //拿了次数减少
    	end
     	
    assign predict_taken=pht1[ad2];  //根据pht1[], hash概率taken
    always@(posedge clk or posedge areset)
        if(areset)
            predict_history<=7'b0;
    	else if(train_valid&train_mispredicted)
            predict_history<={train_history[5:0],train_taken};//用计算结果
        else if(predict_valid)
            predict_history<={predict_history[5:0],predict_taken};//用预测结果
    	
endmodule