`timescale 1ns / 1ps `default_nettype none // ----------------------------------------------------------------------------- // 八表项全相联分支目标缓冲(BPB/BTB)。 // // tag = PC[11:2],与 Logisim 版 BPB 中的十位 tag 拆分保持一致。 // count 为两位饱和计数器:00/01 表示不跳转,10/11 表示跳转。 // age 用于近似 LRU 替换:被选中的表项清零,其余表项自增。 // ----------------------------------------------------------------------------- module cpu21_bpb_8 ( input wire clk, input wire reset, input wire [31:0] predict_pc, input wire predict_enable, output reg predict_hit, output reg predict_taken, output reg [31:0] predict_target, input wire update_enable, input wire update_controlflow, input wire [31:0] update_pc, input wire [31:0] update_target, input wire update_taken ); reg valid [0:7]; reg [ 9:0] tag [0:7]; reg [31:0] target [0:7]; reg [ 1:0] count [0:7]; reg [ 2:0] age [0:7]; reg update_found; reg [ 2:0] update_index; reg replace_found; reg [ 2:0] replace_index; reg [ 2:0] max_age; integer p; integer u; integer k; integer selected_index; // 预测命中查找:按 tag 全相联匹配,命中则给出目标地址与方向预测。 always @* begin predict_hit = 1'b0; predict_taken = 1'b0; predict_target = 32'b0; for (p = 0; p < 8; p = p + 1) begin if (predict_enable && !predict_hit && valid[p] && (tag[p] == predict_pc[11:2])) begin predict_hit = 1'b1; predict_target = target[p]; predict_taken = count[p][1]; end end end // 更新时先找匹配表项;若无匹配则优先使用无效表项,否则淘汰最旧表项。 // 下方的 age 自增实现了类似 LRU 的替换策略。 always @* begin update_found = 1'b0; update_index = 3'd0; replace_found = 1'b0; replace_index = 3'd0; max_age = 3'd0; for (u = 0; u < 8; u = u + 1) begin if (!update_found && valid[u] && (tag[u] == update_pc[11:2])) begin update_found = 1'b1; update_index = u; end end for (u = 0; u < 8; u = u + 1) begin if (!replace_found && !valid[u]) begin replace_found = 1'b1; replace_index = u; end else if (!replace_found && (age[u] >= max_age)) begin replace_index = u; max_age = age[u]; end end end // 表项状态更新(含替换与两位饱和计数器更新)。 always @(posedge clk or posedge reset) begin if (reset) begin for (k = 0; k < 8; k = k + 1) begin valid[k] <= 1'b0; tag[k] <= 10'b0; target[k] <= 32'b0; count[k] <= 2'b01; age[k] <= 3'b0; end end else if (update_enable && update_controlflow) begin selected_index = update_found ? update_index : replace_index; valid[selected_index] <= 1'b1; tag[selected_index] <= update_pc[11:2]; target[selected_index] <= update_target; age[selected_index] <= 3'b0; if (!update_found) begin // 新表项采用较弱的初始状态,避免立刻产生错误预测。 count[selected_index] <= update_taken ? 2'b10 : 2'b01; end else if (update_taken) begin // 实际跳转:计数器加一(饱和到 11)。 if (count[selected_index] != 2'b11) count[selected_index] <= count[selected_index] + 2'b01; end else begin // 实际不跳转:计数器减一(饱和到 00)。 if (count[selected_index] != 2'b00) count[selected_index] <= count[selected_index] - 2'b01; end for (k = 0; k < 8; k = k + 1) begin if (valid[k] && (k != selected_index) && (age[k] != 3'b111)) age[k] <= age[k] + 3'b001; end end end endmodule `default_nettype wire