刷完HDLbits后一段时间没关注了,偶然发现最近更新了。
新增加的四道题都和处理器分支预测相关,正好我之前有相关经验,借此机会重温一下
uwaterloo cs450 这几道题看起来是 滑铁卢大学cs450 计算机体系结构课程相关的题目,整体难度不大。
如果不了解相关知识背景可以先参考一下这个wiki Branch_predictor ,讲的不错。
1. Cs450/timer - HDLBits
很简单,实现一个递减计数器,计数器减到0的时候拉高tc,一个counter轻松秒杀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| module top_module( input clk, input load, input [9:0] data, output tc ); reg [9:0] counter; always @(posedge clk) begin if (load) counter <= data; else if (counter > 0) counter <= counter - 1; end assign tc = !counter; endmodule
|
2. Cs450/counter 2bc
实现饱和计数器,四个状态,说白了taken=1就往强选择状态移动,taken=0往强不选状态移动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| module top_module( input clk, input areset, input train_valid, input train_taken, output reg [1:0] state ); always @(posedge clk, posedge areset) begin if (areset) state <= 2'b01; else if (train_valid) begin if (train_taken) state <= (state == 2'b11) ? 2'b11 : (state + 1); else state <= (state == 2'b00) ? 2'b00 : (state - 1); end end endmodule
|
3. Cs450/history shift
历史缓冲区,作用就是记录最近跳转的信息,供预测器使用。值得注意的就是当发生预测失败,需要冲刷流水线,在预测失败之后的预测(younger)都需要从历史缓冲区中冲刷掉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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 ); always @(posedge clk, posedge areset) begin if (areset) predict_history <= 0; else if (train_mispredicted) predict_history <= {train_history[30:0], train_taken}; else if (predict_valid) predict_history <= {predict_history[30:0], predict_taken}; end endmodule
|
注意 预测失败的优先级高于预测使能信号,预测失败会冲刷出错之后全部的历史。
4. Cs450/gshare - HDLBits
本题相对比较复杂,需要实现一个gshare。
产生predict_taken的方式是通过一个叫模式匹配表(pattern history table, PHT)的东西
首先题目中历史缓冲区为7个bit,因此PHT的大小为2^7 = 128个。
pattern为 7bit历史缓冲区和7bit程序计数器(PC)按位异或,每个pattern对应一个2bit饱和计数器
PHT[history ^ pc] = 2'b01;
模块可以分成training和predicting两部分,分别由train_valid和predict_valid两个信号控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| module top_module( input clk, input areset,
input predict_valid, input [6:0] predict_pc, output predict_taken, output reg [6:0] predict_history,
input train_valid, input train_taken, input train_mispredicted, input [6:0] train_history, input [6:0] train_pc ); reg [1:0] PHT[127:0]; integer i; always @(posedge clk, posedge areset) begin if (areset) begin predict_history <= 0; for (i=0; i<128; i=i+1) PHT[i] <= 2'b01; end else begin if (train_valid && train_mispredicted) predict_history <= {train_history[6:0], train_taken}; else if (predict_valid) predict_history <= {predict_history[6:0], predict_taken}; if (train_valid) begin if (train_taken) PHT[train_history ^ train_pc] <= (PHT[train_history ^ train_pc] == 2'b11) ? 2'b11 : (PHT[train_history ^ train_pc] + 1); else PHT[train_history ^ train_pc] <= (PHT[train_history ^ train_pc] == 2'b00) ? 2'b00 : (PHT[train_history ^ train_pc] - 1); end end end assign predict_taken = PHT[predict_history ^ predict_pc][1]; endmodule
|
总体来说,这几个题目相对其他题目不在拘泥于verilog基本语法,更多结合一些处理器的实现,有一些实用意义。