分支目标缓存 — BTB

分支目标缓存命中

📖 为什么需要BTB?

2位预测器只预测方向(taken/not-taken),但不知道跳转目标地址。分支目标缓存(Branch Target Buffer, BTB)缓存每个分支的目标地址,使得在取指阶段就能知道下一条指令的地址,避免1-2周期的流水线气泡。

BTB工作原理: 取指阶段: PC → BTB查找 命中 + taken → 下一个PC = BTB[PC].target 未命中 → 下一个PC = PC + 4 BTB结构: ┌────────┬────────┬────────┬────────┐ │ Tag │ Valid │ Target │Predict │ │ (6bit) │ (1bit) │(32bit) │ (1bit) │ ├────────┼────────┼────────┼────────┤ │ 0x25 │ 1 │ 0x200 │ 1 │ │ 0x3A │ 1 │ 0x400 │ 0 │ │ ... │ 0 │ ... │ 0 │ └────────┴────────┴────────┴────────┘ 1周期完成: PC → 索引 → 比较Tag → 输出target vs 无BTB: 需要执行阶段才知道target (2-3周期浪费)
BTB大小命中率面积功耗
32项~80%
64项~90%
256项~95%
512项~97%很大

直接映射 vs 组相联

本课实现的是直接映射BTB:每个PC映射到唯一一个条目。优点是简单快速,缺点是冲突失效(两个PC映射到同一位置)。高性能处理器使用2-way或4-way组相联BTB。

Return Address Stack (RAS)

函数返回(JALR x1)的目标地址每次不同,BTB无法有效预测。RAS是一个小栈,在函数调用时push返回地址,返回时pop。RAS对函数调用的预测准确率接近100%。

BOOM处理器使用BTB+RAS+Tage的组合:BTB提供目标地址,Tage提供方向预测,RAS专门处理函数返回。

🖥️ Verilog实现

// Lesson 21: Branch Target Buffer
module branch_target_buffer #(parameter NUM_ENTRIES=64, IDX_BITS=6, TAG_BITS=8, XLEN=32)(
    input wire clk, rst_n, input wire [31:0] lookup_pc,
    output reg hit, output reg [31:0] target,
    input wire update_valid, input wire [31:0] update_pc, update_target, input wire update_taken);
    reg [TAG_BITS-1:0] tags [0:NUM_ENTRIES-1]; reg [31:0] targets [0:NUM_ENTRIES-1];
    reg valid [0:NUM_ENTRIES-1]; integer i;
    wire [IDX_BITS-1:0] idx=lookup_pc[IDX_BITS+1:2];
    wire [TAG_BITS-1:0] tag=lookup_pc[IDX_BITS+TAG_BITS+1:IDX_BITS+2];
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) for(i=0;i<NUM_ENTRIES;i=i+1) begin valid[i]<=0; tags[i]<=0; targets[i]<=0; end
        else if (update_valid) begin tags[update_pc[IDX_BITS+1:2]]<=update_pc[IDX_BITS+TAG_BITS+1:IDX_BITS+2];
            targets[update_pc[IDX_BITS+1:2]]<=update_target; valid[update_pc[IDX_BITS+1:2]]<=1; end end
    always @(*) if(valid[idx]&&tags[idx]==tag) begin hit=1; target=targets[idx]; end
        else begin hit=0; target=lookup_pc+4; end
endmodule
Verilator仿真验证通过 — BTB命中输出正确目标地址,未命中返回PC+4

代码解析

📊 BTB与分支预测的协同

完整分支预测系统: Fetch阶段: PC ──→ BTB ──→ (hit, target) ──→ PC ──→ BHT(2-bit) ──→ (taken?) ──→ PC ──→ RAS ──→ (return?) ──→ ↓ MUX: 选择下一个PC • BTB hit + taken → BTB.target • RAS hit (JALR) → RAS.top • Default → PC + 4 Execute阶段: 实际结果 → 更新BTB, BHT, RAS 预测错误 → 冲刷流水线 + 修复

🧪 实验练习

  1. 在当前实现基础上添加异常处理支持
  2. 实现流水线仿真,观察波形中的关键信号变化
  3. 添加性能计数器:统计吞吐量、延迟、利用率
  4. 前几课的模块集成,构建更完整的系统
分支目标缓存命中 — BTB消除分支目标计算延迟
思考题:直接映射BTB的冲突失效如何解决?2-way组相联BTB需要多少额外硬件?
参考资料:Hennessy & Patterson §3.3 | BTB设计原理 | BOOM Branch Prediction

📚 深入理解与实践建议

掌握本课内容需要结合理论学习和动手实践:

  1. 阅读源码:BOOM(Chisel)和Rocket(Chisel)是RISC-V处理器设计的最佳参考实现
  2. 修改实验:修改本课的Verilog代码,观察行为变化
  3. 波形仿真:使用GTKWave查看关键信号的时序关系
  4. 对比分析:将本课模块与前几课模块集成,测试端到端功能

开发环境

工具用途安装
Verilator 5.020Verilog编译仿真sudo apt install verilator
iverilog轻量仿真sudo apt install iverilog
GTKWave波形查看sudo apt install gtkwave
RISC-V GCC交叉编译apt install gcc-riscv64-unknown-elf
QEMU系统仿真apt install qemu-system-misc

📖 推荐阅读

在线资源

🔧 开发工具链与实践环境

本课程推荐以下开发工具链:

工具用途安装命令
VerilatorVerilog编译/仿真sudo apt install verilator
iverilog轻量Verilog仿真sudo apt install iverilog
GTKWave波形查看sudo apt install gtkwave
RISC-V GCC交叉编译apt install gcc-riscv64-unknown-elf
QEMU系统仿真apt install qemu-system-misc
SpikeISA模拟器从源码编译

快速验证

# 编译本课Verilog代码
cd verilog/
iverilog -o tb_test *.v
vvp tb_test

# Verilator lint检查
verilator --lint-only -Wno-BLKLOOPINIT *.v

# 应无Error输出

🎯 课程知识体系

RISC-V高级设计课程 (30课): 基础(L01-06): 特权架构→CSR→异常→中断→PLIC→CLINT 内存(L07-12): SV39 MMU→TLB→Cache系列 算术(L13-14): 乘法器→除法器 乱序(L15-19): OoO核心→ROB→寄存器重命名→记分牌→Tomasulo 预测(L20-21): 2位预测→BTB 扩展(L22-26): RVC→RVM→RVA→RVF→RVD 系统(L27-30): PMP→解码器→SoC→启动流程 每一课都是下一课的基础: 没有特权架构 → 无法理解CSR 没有CSR → 无法实现异常处理 没有异常处理 → 无法实现中断 没有中断 → 无法实现PLIC/CLINT 没有虚拟内存 → 无法运行Linux 没有Cache → 性能灾难 没有乱序执行 → ILP受限 没有分支预测 → 流水线气泡严重

🔬 实验扩展:进阶挑战

完成基础实验后,尝试以下进阶挑战:

  1. 性能优化:使用流水线技术减少关键路径延迟
  2. 面积优化:资源共享、操作数合并、时钟门控
  3. 功耗优化:添加时钟门控、操作数隔离
  4. 形式验证:使用Yosys formal验证功能正确性
  5. FPGA综合:在Xilinx/Intel FPGA上实现并测量时序

调试技巧

🎯 课程知识体系

RISC-V高级设计课程 (30课): 基础(L01-06): 特权架构→CSR→异常→中断→PLIC→CLINT 内存(L07-12): SV39 MMU→TLB→直接映射Cache→组相联→写回→分离Cache 算术(L13-14): Booth乘法器→恢复余数除法器 乱序(L15-19): OoO核心→ROB→寄存器重命名→记分牌→Tomasulo 预测(L20-21): 2位饱和计数器→BTB分支目标缓冲 扩展(L22-26): RVC压缩→RVM乘除→RVA原子→RVF单精度→RVD双精度 系统(L27-30): PMP保护→全解码器→SoC集成→启动流程

本课是第21课,在整体课程中承上启下。每一课都构建在前一课的基础上,建议按顺序学习。

📚 推荐阅读

在线资源