哈工大计算机体系结构课程实验——分支预测 实验分享
这个实验让人有些出乎意料,不是因为太难,而是因为太简单了,代码量很少,构思也很简单,看看课本对应内容就可以上手了,实现方法有很多,我使用的是最简单的BPB+BTB,仅供参考。
总体构思
实验要求放在这里,说的很清晰,需要我们实现的只有一个模块branch_predictor,需要根据它给出的接口实现分支预测功能,其他的不需要管。
实验报告提出了几种实现方法,最简单也是最容易实现的还是BTB+BPB,课本对相关技术介绍的很明白了。
总体来说,就是定义一个BTB表,里面存放着一些指令信息,比如转移指令的PC值、转移指令目的PC值等等,根据实验报告,可以将其设置为PC[7:2]位寻址,也就是类似直接映射模式,每条指令只能存储在特定的位置,在后续查询比对的时候也只需要和这一个位置的数据进行对比,非常方便。
另外BPB可以看看上面的图,跳转与否根据BPB的值。
实现方法
我并没有区分BTB与BPB两个寄存器数组,而是只定义了一个寄存器数组,与一条指令相关的所有信息全部存储在里面。
初始时,整个BTB表是空的,我们的分支预测此时也不可以工作,所以我们利用模块给出的upd返回接口对我们的BTB表进行填充,当我们返回来的指令是跳转指令的时候,我们就把指令PC以及目的PC放进BTB表。
后续就可以根据BTB表的内容进行预测了。
比较简单,代码我也做了注释,很容易看懂。
实现代码
`timescale 1ns / 1ps
module branch_predictor(
input clk, //时钟信号,必须与CPU保持一致
input resetn, //低有效复位信号,必须与CPU保持一致
//供CPU第一级流水段使用的接口:
input[31:0] old_PC, //上一个指令地址
input predict_en, //这周期是否需要更新PC(进行分支预测)
output[31:0] new_PC, //预测出的下一个指令地址
output predict_jump, //是否被预测为执行转移的转移指令
//分支预测器更新接口:
//更新使能
input upd_en,
//转移指令地址
input[31:0] upd_addr,
//是否为转移指令
input upd_jumpinst,
//若为转移指令,则是否转移
input upd_jump,
//是否预测失败
input upd_predfail,
//转移指令本身的目标地址(无论是否转移)
input[31:0] upd_target
);
reg [65:0]BTB[63:0]; //创建一个根据PC[7:2]寻址的BTB表项,相当于直接映射后续寻找只需要对比一个项就可以
integer i;
initial begin
for (i = 0; i < 64; i = i + 1) begin
BTB[i] = 66'h0; //必须全部初始化,不能存在XXXXX,否则最后assign赋值会赋值失败
end
for(i=0;i<64;i=i+1) begin
BTB[i][1:0]=2'b11; //将BPB两位初始化为11
end
end
/*为BTB赋值,BTB初始时没有任何信息,之后随着upd反馈来添加转移指令以及转移目标*/
always @(posedge clk) begin
if(upd_en==1'b1&&upd_jumpinst==1'b1&&BTB[upd_addr[7:2]][33:2]==32'h0) begin //只有在指定位置全是0才能进行赋值,不是0代表已经存在指令
BTB[upd_addr[7:2]][33:2]=upd_addr; //存储转移PC
BTB[upd_addr[7:2]][65:34]=upd_target; //存储目的PC
end
end
always @(upd_en) begin //根据转移结果调整两位BPB
if(upd_jumpinst==1'b1&&upd_en==1'b1&&upd_addr==BTB[upd_addr[7:2]]) begin //更新条件
if(upd_predfail==1'b1) begin //预测失败而更新
if(BTB[upd_addr[7:2]][1:0]==2'b00) begin
BTB[upd_addr[7:2]][1:0]<=2'b00;
end
else if(BTB[upd_addr[7:2]][1:0]==2'b01) begin
BTB[upd_addr[7:2]][1:0]<=2'b00;
end
else if(BTB[upd_addr[7:2]][1:0]==2'b10) begin
BTB[upd_addr[7:2]][1:0]<=2'b00;
end
else if(BTB[upd_addr[7:2]][1:0]==2'b11) begin
BTB[upd_addr[7:2]][1:0]<=2'b10;
end
end
else if(upd_predfail==1'b0) begin //预测成功而更新
if(BTB[upd_addr[7:2]][1:0]==2'b00) begin
BTB[upd_addr[7:2]][1:0]<=2'b01;
end
else if(BTB[upd_addr[7:2]][1:0]==2'b01) begin
BTB[upd_addr[7:2]][1:0]<=2'b11;
end
else if(BTB[upd_addr[7:2]][1:0]==2'b10) begin
BTB[upd_addr[7:2]][1:0]<=2'b11;
end
else if(BTB[upd_addr[7:2]][1:0]==2'b11) begin
BTB[upd_addr[7:2]][1:0]<=2'b11;
end
end
end
end
//预测开始
assign new_PC=(old_PC!=32'b0&&old_PC==BTB[old_PC[7:2]][33:2]&&predict_en==1'b1&&(BTB[old_PC[7:2]][1:0]==2'b10||BTB[old_PC[7:2]][1:0]==2'b11))? BTB[old_PC[7:2]][65:34]:old_PC+4;
assign predict_jump=(old_PC!=32'b0&&old_PC==BTB[old_PC[7:2]][33:2]&&predict_en==1'b1&&(BTB[old_PC[7:2]][1:0]==2'b10||BTB[old_PC[7:2]][1:0]==2'b11))? 1'b1:1'b0;
endmodule
结尾
这次实验没什么挑战性,下周估计更新lab3cache
理性借鉴,欢迎交流!
2 条评论
太强了!
是这次太简单了