从零开始设计riscv cpu记录之七

一、这是一份BTB模块代码

c 复制代码
`timescale 1ns / 1ps

`include "defines.v"

module btb #(
    parameter ENTRY_NUM  =128,
    parameter INDEX_W =7
    

    )(
        input  wire clk  ,
        input  wire rst  ,
        
        //from pc_reg
        input  wire [`AW-1:0] lookup_pc_i  ,        
        output wire           hit_o        ,
        output wire [`AW-1:0] target_o     ,
        output wire           is_uncond_o  ,  // jal jalr unconditional jump
        output wire           is_return_o  ,
         
        input  wire           update_valid_i    ,
        input  wire [`AW-1:0] update_pc_i       ,
        input  wire [`AW-1:0] update_target_i   ,
        input  wire           update_is_uncond_i,
        input  wire           update_is_return_i
    
    );
    localparam TAG_W = `AW-INDEX_W - 2;
    
    reg             valid_r     [0:ENTRY_NUM-1]  ;
    reg [TAG_W-1:0] tag_r       [0:ENTRY_NUM-1]  ;
    reg [`AW-1:0]   target_r    [0:ENTRY_NUM-1]  ;
    reg             is_uncond_r [0:ENTRY_NUM-1]  ;
    reg             is_return_r [0:ENTRY_NUM-1]  ;
    
    wire [INDEX_W-1:0]  lookup_index = lookup_pc_i[INDEX_W+1:2];
    wire [TAG_W-1:0]    lookup_tag  = lookup_pc_i[`AW-1:INDEX_W+2];
    wire [INDEX_W-1:0]  update_index = update_pc_i[INDEX_W+1:2];
    wire [TAG_W-1:0]    update_tag  = update_pc_i[`AW-1:INDEX_W+2];
    
    
    wire hit = valid_r[lookup_index]&&   lookup_tag  == tag_r[lookup_index] ;
    assign hit_o = hit;
    
    assign is_uncond_o  = is_uncond_r[lookup_index];
    assign target_o     = target_r[lookup_index];
    assign is_return_o = is_return_r[lookup_index];

    
    integer i;
    always @(posedge clk) begin
       if (rst == `RstEnable) begin
           for (i = 0; i < ENTRY_NUM; i = i + 1) begin
               valid_r[i]     <= 1'b0;
               tag_r[i]       <= {TAG_W{1'b0}};
               target_r[i]    <= `ZeroWord;
               is_uncond_r[i] <= 1'b0;
               is_return_r[i] <= 1'b0;
           end
       end else if (update_valid_i) begin
           valid_r[update_index]     <= 1'b1;
           tag_r[update_index]       <= update_tag;
           target_r[update_index]    <= update_target_i;
           is_uncond_r[update_index] <= update_is_uncond_i;
           is_return_r[update_index] <= update_is_return_i;
       end
    end
    
endmodule

二、BTB结构

Index valid tag22:0 target31:0 is_uncond is_return
0 1 0x000001 0x0000_0800 0 0
1 1 0x000002 0x0000_1200 1 0
2 0 0x000000 0x0000_0000 0 0
3 1 0x000005 0x0000_1A00 0 1
4 0 0x000000 0x0000_0000 0 0
5 1 0x00000A 0x0000_2C00 1 0
6 0 0x000000 0x0000_0000 0 0
7 0 0x000000 0x0000_0000 0 0
... ... ... ... ... ...
123 0 0x000000 0x0000_0000 0 0
124 1 0x001F4A 0x0004_D200 0 1
125 0 0x000000 0x0000_0000 0 0
126 0 0x000000 0x0000_0000 0 0
127 1 0x002B1C 0x0008_1000 1 0

对应的代码:

c 复制代码
    reg             valid_r     [0:ENTRY_NUM-1]  ;
    reg [TAG_W-1:0] tag_r       [0:ENTRY_NUM-1]  ;
    reg [`AW-1:0]   target_r    [0:ENTRY_NUM-1]  ;
    reg             is_uncond_r [0:ENTRY_NUM-1]  ;
    reg             is_return_r [0:ENTRY_NUM-1]  ;

要注意:表格中的index是逻辑抽象出来的,并没有物理结构,只是为了展示BTB有多少项

三、问题是valid除了在rst置为0之外没有别的把他置为0,那能不能去掉呢?节省资源

四、结论是不能。虽然在运行起来之后valid就一直是1,但是不能去掉。因为在刚开始的时候要用到。

五、去掉 valid 会发生什么

复位后数组的初始状态是:valid=0, tag=0, target=0x0

如果没有 valid 参与判定,命中条件就只剩:

verilog 复制代码
hit = (lookup_tag == tag_r[lookup_index]);  // 未分配的项 tag = 0

于是所有 tag 为 0 的 PC 都会假命中

tag = pc[31:9]TAG_W = 32 - 7 - 2 = 23),也就是说 PC < 0x200 的任何分支 ,查到未初始化的项都会"命中",然后拿到 target = 0x0------取指直接跳回地址 0。而复位向量就在低地址,等于启动阶段必然踩雷


六、具体例子说明

假设条件

参数
复位向量地址 0x0000_0000
BTB 复位后状态 所有 entry: tag=0, target=0x0000_0000
分支指令地址 PC = 0x0000_0100(在 .text 段早期,tag 计算后为 0)

执行流程

时钟周期 事件 结果
T0 取指 PC = 0x100,查 BTB lookup_index = 0x100[8:2] = 0x20<br>lookup_tag = 0x100[31:9] = 0
T1 比较:lookup_tag(0) == tag_r[0x20](0) 假命中! (没有 valid 过滤)
T2 target_o = 0x0000_0000 下一条取指地址变成复位向量
T3 CPU 跳回地址 0 无限循环在复位向量附近,程序跑飞

> ⚠️ 这就是"假命中"的灾难 :一个从未被训练过的分支,因为 tag 恰好为 0,被当成已训练的分支,跳转到一个完全错误的目标地址。

相关推荐
何事误红尘2 小时前
ZYNQ学习FPGA笔记(一):vivado安装、XC7Z045
fpga开发
zlinear数据采集卡20 小时前
D223的SRAM硬件记录仪:外部触发与瞬态波形捕获方案
arm开发·嵌入式硬件·fpga开发·开源
szxinmai主板定制专家1 天前
基于 RK3588 + Xilinx Kintex-7 FPGA 异构工业主控板设计方案
arm开发·人工智能·嵌入式硬件·fpga开发·zynq
Rambo.xia1 天前
RFSoC高速采集卡设计项目:一块板卡串联综合优化5大核心技术
单片机·嵌入式硬件·fpga开发
XMAIPC_Robot1 天前
RK3588+STM32:高性能机器人运动控制解决方案,兼顾实时性与AI算力
人工智能·stm32·嵌入式硬件·算法·fpga开发·机器人·arm+fpga
zlinear数据采集卡1 天前
D223的DDS信号发生器:10000点查找表与4通道16位DAC波形输出
arm开发·嵌入式硬件·fpga开发·开源
物质波波波2 天前
WS-RPE:面向边缘物理AI实时特征值计算的硬件工作窃取调度器与冗余PE激活架构
人工智能·fpga开发·架构·系统架构·硬件架构
我爱C编程2 天前
基于FPGA的DSB调制解调系统verilog开发
fpga开发·verilog·fpga·dsb
zlinear数据采集卡2 天前
USB HS 480M高速传输与SRAM记录仪:DABM-D223数据存储系统全解析
arm开发·嵌入式硬件·fpga开发·开源
逻辑诗篇2 天前
基于 XCVU13P 的 4 路 100G 光纤 PCIe 处理板 PCIE727 硬件规格全解析
fpga开发