这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

重要结构及接口文档

本文档将会对 BPU 中的重要结构以及对外接口进行描述,描述粒度将深入代码级别,通过阅读本文档,你可以理解香山分支预测单元中每一个信号是什么作用,理解各种请求的具体实现方式,也将使你能够结合代码进行功能的理解。

本文档将会对 BPU 中的重要结构以及对外接口进行描述,描述粒度将深入代码级别,文档中描述的结构将与香山分支预测单元 Chisel 版本代码保持一致,信号结构及名称亦来自于 Chisel 版本代码。

文档适用于已经了解了香山分支预测单元基础设计,并想要深入了解信号细节的同学使用。可以根据验证需要的内容有选择的进行阅读,或随时进行查阅。

其中,FTB项与完整预测结果接口涉及 BPU 产生预测结果的方式,建议每位同学进行阅读。

1 - FTB项与完整预测结果接口

BPU 的基本预测单位是分支预测块,然而分支预测块的结构是怎样的呢?为什么一个分支预测块可以指导接下来如此多条指令的执行呢?这一部分将讲述生成分支预测块的核心数据结构——FTB项,以及由 FTB 项生成的完整预测结果结构。

FTB 项

FTB 项是香山中分支预测块的核心数据结构,它存储了生成一个分支预测块所需的信息。在BPU进行预测时,初始的分支预测块首先由一个读出的 FTB 项生成。然后,这个分支预测块会传递到后续的预测器中,后续的预测器会读取其中的信息并加以修改,生成最终的预测结果。

因此,要理解分支预测块的结构,首先需要理解FTB项的结构。一个FTB项对应着一个分支预测块,其大致结构如下:

首先,需要明确一个信息:无论是分支预测块还是FTB项,它们可以容纳的指令数量都被设定为一个特定的上限(在香山当前版本中为16条RVC指令),被称为最大预测长度。这意味着,如果我们需要记录分支预测块内某一条指令的位置,可以使用一个固定长度的位向量,来指定这条指令相对于预测块起始地址的偏移量。

分支预测块执行流程的决定因素是其中的分支指令信息。其余的指令都被视为普通指令,不影响程序的执行流。因此,在一个分支预测块中,我们只需记录下其中的分支指令位置即可,而普通指令的位置我们并不关心。

因此,FTB项中定义了两种类型的分支指令槽(slot)——brSlotstailSlot,用于存储分支预测块中的分支指令。目前香山版本中,brSlots只含有一个 slot,而 tailSlot 则是一个单独的 slot,总计含有两个 slot。

在最大预测长度内的指令中,如果出现了分支指令,FTB项会将其记录在对应的slot内,并将该slot置为有效。如果分支指令出现过多,达到了FTB项的容纳上限,那么超出上限的分支指令则会交给下一个FTB项来存储。在每个 slot中,我们会记录一条分支指令相对于预测块起始地址的偏移量(offset),同时还会记录其跳转目标地址等信息。

唯一的 tailSlot

在RISC-V中,分支指令主要分为两种类型:条件分支和无条件跳转。因此,对于一个分支预测块来说,最多只会包含一条无条件跳转指令。因为一旦执行到这条指令,程序的执行流就会发生改变,后续的指令将不再执行。因此,我们定义了一种类型的 slot 叫做 tailSlot,专门用来存储这条无条件跳转指令。而对于条件分支指令,则将它们存储在brSlots中。

tailSlot如其名,位于整个预测块中的最后一个 slot。这也是因为一旦填充了无条件跳转指令,程序必定跳转,之后的指令就由其他预测块进行处理,因此后续的指令情况我们无需关心。但在无条件跳转指令之前的指令中,我们需要关心是否存在条件分支指令,因为条件分支指令既有可能跳转,也有可能不跳转。因此,我们需要记录下条件分支指令的相关信息。

tailSlot 共享

考虑一种情况:如果从预测块起始PC开始直到最大预测长度,都没有出现无条件跳转指令,反而出现了两条条件分支指令,这样一来,tailSlot 就会空闲,而第二条条件分支指令又无法存储,造成空间的浪费。

为了解决这个问题,香山采用了一种方法:设置一个 sharing 标记。我们可以直接将第二条分支指令存储到tailSlot 中,并将sharing标记设置为真,表示第二条条件分支指令共享了无条件跳转指令的 tailSlot。这样,就有效利用了tailSlot的空间。

预测块中的 isCallisRetisJalr字段是为tailSlot服务的。如果tailSlot中记录的是无条件跳转指令,这几个字段会进一步指示该跳转指令的类型。在FTB项中还有一个字段 always_taken,用来记录每个Slot中存储的条件分支指令是否总是被预测为跳转。如果是的话,后续的预测器可以直接采用这一预测结果。

通过FTB项,我们可以得知一个分支预测块中的指令情况,包括分支指令的位置、类型等。这些信息会交给后续的预测器,由后续的预测器来预测更为精确的跳转目标、是否跳转等信息。

FTB 项完整结构 (FTBEntry)

接口定义: src/main/scala/xiangshan/frontend/FTB.scala

本节中描述了 FTB 项的完整结构定义,其所含的信号如下:

  • valid: FTB表项是否有效。
    • 接口类型: Bool
  • brSlots: 条件分支指令槽。
    • 接口类型: Vec(numBrSlot, new FtbSlot(BR_OFFSET_LEN)) (接口列表详见FtbSlot)
  • tailSlot: 无条件跳转指令槽。
    • 接口类型: new FtbSlot(JMP_OFFSET_LEN, Some(BR_OFFSET_LEN)) (接口列表详见FtbSlot)
  • pftAddr: 预测块的结束地址。
    • 接口类型: UInt(log2Up(PredictWidth).W)
  • carry: 预测块的结束地址进位。
    • 接口类型: Bool()
  • isCall: 无条件跳转指令槽中的指令为 call 指令。
    • 接口类型: Bool()
  • isRet: 无条件跳转指令槽中的指令为 ret 指令。
    • 接口类型: Bool()
  • isJalr: 无条件跳转指令槽中的指令为 jalr 指令。
    • 接口类型: Bool()
  • last_may_be_rvi_call: 无条件跳转指令槽中的指令可能为一个 RVI 类型的 call 指令信号。
    • 接口类型: Bool()
  • always_taken: 该预测块中的每个分支指令是否总是被预测为 Taken。
    • 接口类型: Vec(numBr, Bool())

说明:pftAddr 和 carry

在这里,pftAddr是Partial Fallthrough Addr的缩写。Fallthrough Addr 表示,如果预测块中没有跳转,那么程序将会顺序执行到达的地址。换句话说,如果一条无条件跳转指令的偏移为5,那么 Fallthrough Addr 对应的偏移便是6。这一信号主要用于获取函数调用后程序的返回地址,可以将这一概念理解为预测块的结束地址。

Partial 表示部分地址,这是由地址的表示方法决定的。在这里,地址的表示方法如下:

  pc: | ... |<-- log(predictWidth) -->|<-- log(instBytes) -->|
           ^                         ^
           |                         |
           carryPos                  instOffsetBits

pftAddr 便是只记录了中间的偏移部分(即长度为 log(predictWidth) 的部分),之后结合当前 PC 才能生成完整 PC。但由于有可能产生进位,因此单独记录一个 carry 位,carryPos 是预测块中的指令地址中 会产生进位的位置

另外,last_may_be_rvi_call 也是对该地址的一个辅助信号,表示无条件跳转指令槽中的指令是一个RVI类型的 call 指令。由于pftAddr在计算时默认认为指令长度为压缩指令长度,因此计算结束地址只会加 2 字节。但如果实际的call指令并不是压缩指令,就会导致返回地址计算错误。RAS会根据这一信号修正这个错误。

分支预测槽 (FTBSlot)

接口定义: src/main/scala/xiangshan/frontend/FTB.scala

该接口定义了 FTB 表项中 slot:

  • offset: 该 slot 中指令相对于预测块起始地址的偏移
    • 接口类型:UInt(log2Ceil(PredictWidth).W)
  • lower: 跳转目标地址的低位。
    • 接口类型:UInt(offsetLen.W)
    • 说明:这里设置 lower 为 12 位或 20 位,因为分支指令的寻址能力为 12 位,而跳转指令的寻址能力为 20 位
  • tarStat: 跳转后的 pc 高位是否进退位
    • 接口类型:UInt(TAR_STAT_SZ.W)(TAR_STAT_SZ = 2)
    • 说明:跳转目标地址由当前 PC 的高位、tarState 以及 lower 字段共同计算得出,其中,lower 字段直接存储了跳转目标地址的低位。当前的 PC 高位经过 tarStat 指导进行进退位之后,直接与 lower 拼接便可得到真正的跳转目标地址。tarStat 共有三个可能的取值:0 - 不进不退, 1 - 进位, 2 - 退位。
  • sharing: 无条件跳转指令槽中存储了一条条件分支指令。
    • 接口类型:Bool()
  • valid: slot 有效位。
    • 接口类型:Bool()

完整分支预测结果 (FullBranchPrediction)

  • 接口定义: src/main/scala/xiangshan/frontend/FrontendBundle.scala

该接口定义了完整的分支预测结果,每流水级预测结果中都会包含该接口。

完整分支预测结果接口与 FTB 项相差无几,并最初由 FTB 项生成。两个Slot被拆分成了单独的信号:slot_valids, targets, offsets, is_br_sharing 等,另外增加了若干字段例如 br_taken_mask, jar_target 便于后续预测器提供精确预测结果,另外 hit 表示 FTB 项是否命中,即本轮预测中的 PC 索引到了某个 FTB 项。

完整接口列表如下:

  • hit FTB表项是否命中

    • 接口类型:Bool()
  • slot_valids slot有效位,表示 ftb 项中的每个 slot 是否有效

    • 接口类型:Vec(totalSlot, Bool())
  • targets 每个 slot 对应的跳转目标地址

    • 接口类型:Vec(totalSlot, UInt(VAddrBits.W))
  • offsets 每个 slot 中的指令相对于预测块起始地址的偏移

    • 接口类型:Vec(totalSlot, UInt(log2Ceil(PredictWidth).W))
  • fallThroughAddr 预测块的结束地址

    • 接口类型:UInt(VAddrBits.W)
  • fallThroughErr FTB项中记录的 pftAddr 有误

    • 接口类型:Bool()
  • is_jal 预测块内包含jal指令

    • 接口类型:Bool()
  • is_jalr 预测块内包含jalr指令

    • 接口类型:Bool()
  • is_call 预测块内包含call指令

    • 接口类型:Bool()
  • is_ret 预测块内包含ret指令

    • 接口类型:Bool()
  • last_may_be_rvi_call 无条件跳转指令槽中的指令可能为一个 RVI 类型的 call 指令信号。

    • 接口类型:Bool()
  • is_br_sharing 最后一个slot (tailSlot) 中存储的是条件分支指令信号

    • 接口类型:Bool()
  • br_taken_mask 分支预测结果,每个分支(slot)对应一位,表示该分支是否被预测为 taken

    • 接口类型:Vec(numBr, Bool())
  • jalr_target 本预测块中的 jalr 的跳转目标

    • 接口类型:UInt(VAddrBits.W)

2 - 重定向与更新接口

重定向与更新请求是 FTQ 发往 BPU 的两大信息类型,本节中讲述了这两种请求接口的具体结构。

分支预测重定向(BranchPredictionRedirect)

接口定义:src/main/scala/xiangshan/frontend/FrontendBundle.scala

接口类型:BranchPredictionRedirect

该接口定义了分支预测单元的重定向请求,主要用于重定向分支预测器的状态。

BranchPredictionRedirct 接口继承自 Redirct 接口,所含信号较多,BPU 重定向只会用到其中一部分接口,文档描述的结构中只包含 BPU 用到的接口内容。

重定向请求有两种来源,与 IFU 预译码信息对比生成的重定向请求,后端执行过程中的重定向请求。

在重定向请求中,关键信息是cfiUpdate即控制流指令信息。这一信息对应着一条指令,也就是BPU发生预测错误的指令。举例来说,如果 BPU 在预测块中指示第三条指令为普通指令不发生跳转,但预译码显示第三条指令是一条无条件跳转指令,必定会跳转。在这种情况下,BPU 发生了预测错误,FTQ 产生了重定向请求。在重定向请求中,cfiUpdate 将会对应这条无条件跳转指令。

cfiUpdate 中的信息可大致分为三种类型的信息:

  1. 对应指令的信息及执行情况。其中会说明该指令在预测块中位于那个槽 (shift) 及 pc; 会指示这条指令的类型相关信息 (pd);还有这条指令的执行情况,例如跳转目标、是否跳转等
  2. 历史维护相关信息。重定向请求中包含了该条指令所处的预测块对应的分支历史信息,以帮助BPU恢复分支历史信息。foleded_hist 代表全局折叠历史,histPtr 代表全局历史指针,而其余信息则是维护分支历史的辅助信息。要详细了解这些信息的含义,请参阅 BPU顶层模块
  3. RAS维护相关信息。详细含义请参阅 RAS 子预测器文档。

level 信息的含义是,重定向是否包含本条指令,如果不包含,重定向请求的接收方将认为这条指令已经被执行了,下次预测将从下一条指令开始。BPU 顶层会默认不包含本条指令,收到重定向请求后,会将本条指令的执行情况统计到分支历史当中。

以下为重定向接口的详细信号列表:

  • level: 重定向请求是否包括本位置,低表示在本位置后重定向,高表示在本位置重定向。

    • 接口类型: UInt(1.W)
  • cfiUpdate: 控制流指令更新信息

    • 接口类型: CfiUpdateInfo

    • 接口列表

      • pc: 重定向请求对应的指令 PC
        • 接口类型: UInt(VaddrBits.W)
      • pd: 重定向指令的预译码信息
        • isRVC: 是否是压缩指令
          • 接口类型: Bool
        • isCall: 是否是函数调用
          • 接口类型: Bool
        • isRet: 是否是函数返回
          • 接口类型: Bool
      • target: 重定向请求指令的目标地址。
        • 接口类型: UInt(VaddrBits.W)
      • taken: 重定向请求指令是否发生跳转。
        • 接口类型: Bool
      • shift: 重定向请求指令位于哪个槽,如果是普通指令则为0.
        • 接口类型: UInt((log2Ceil(numBr)+1).W)
      • addIntoHist: 重定向请求指令执行信息是否要加入分支历史。
        • 接口类型: Bool

      • folded_hist: 重定向请求对应的折叠历史。
        • 接口类型: AllFoldedHistories(foldedGHistInfos)
      • afhob: 重定向请求指令对应的分支历史最老位。
        • 接口类型: AllAheadFoldedHistoryOldestBits(foldedGHistInfos)
      • lastBrNumOH: 重定向请求对应的上次跳转位置。
        • 接口类型: UInt((numBr+1).W)
      • histPtr: 重定向请求需要恢复的全局历史指针。
        • 接口类型: CGHPtr

      • ssp: 重定向请求指令对应的 RAS 推测栈栈顶在提交栈位置的指针。
        • 接口类型: UInt(log2Up(RasSize).W)
      • sctr: 重定向请求指令对应的 RAS 推测栈栈顶递归计数 Counter。
        • 接口类型: UInt(log2Up(RasCtrSize).W)
      • TOSW: 重定向请求指令对应的 RAS 推测栈(队列)写指针。
        • 接口类型: CGHPtr
      • TOSR: 重定向请求指令对应的 RAS 推测栈(队列)读指针。
        • 接口类型: CGHPtr
      • NOS: 重定向请求指令的 RAS 栈顶 Counter。
        • 接口类型: CGHPtr

分支预测更新(BranchPredictionUpdate)

接口定义: src/main/scala/xiangshan/frontend/FrontendBundle.scala

该接口定义了分支预测器的更新请求,主要用于更新分支预测器的状态,文档只列出了在 BPU 中使用的接口。

更新请求与每一个分支预测块一一对应,当 FTQ 中的一个分支预测块被执行过以后,FTQ 将会为这个分支预测块产生一个更新请求,来指导预测器进行训练,因此更新请求中的一个重要职责就是向 BPU 反馈指令的真实执行情况。当然在香山分支预测单元中,更新请求还会负责 FTB 项的更新

更新请求中的信息可大致分为四类:

  • PC 表示预测块的起始地址,指示了该更新请求对应哪个分支预测块
  • FTB 项更新信息 更新通道中会含有一个 FTB 项结构 (ftb_entry),输出 FTQ 新生成的 FTB 项,并且还会指示是否与旧的 FTB 项相同 (old_entry)
  • 指令真实执行情况信息 更新通道中会指示该分支预测块中分支指令和无条件跳转指令的执行情况,还会给出控制流指令(即发生跳转的指令)的地址以及最终跳转目标。
  • 与该预测块对应的预测器相关数据 包含 spec_info 以及 meta 信息。(具体请参阅BPU全局接口文档)

更新请求的接口列表如下:

  • pc 更新请求的pc (预测块起始地址)
    • 接口类型:UInt(VAddrBits.W)

  • ftb_entry 更新后的ftb项
    • 接口类型:new FTBEntry()
    • 接口列表:详见(FTBEntry
  • old_entry 更新后的 FTB 项是否与旧的 FTB 项相同
    • 接口类型:Bool()

  • br_taken_mask 预测块内每个slot内指令是否跳转
    • 接口类型:Vec(numBr, Bool())
  • mispred_mask 预测块内预测错误的掩码。第一、二位分别代表两个条件分支指令是否预测错误,第三位指示无条件跳转指令是否预测错误。
    • 接口类型:Vec(numBr+1, Bool())
  • jmp_taken 预测块内无条件跳转指令被触发
    • 接口类型:Bool()
  • cfi_idx 控制流指令在预测块中的索引
    • 接口类型:ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
  • full_target 预测块的跳转目标(下一个预测块的起始地址)
    • 接口类型:UInt(VAddrBits.W)

  • spec_info 该预测块对应的 last_stage_spec_info
    • 接口类型:new SpeculativeInfo
    • 接口列表:(只用到了 foled_hist 一项)
      • folded_hist 全局折叠历史
        • 接口类型:AllFolededHistories(foldedGHistInfos)
  • meta 该预测块对应的 last_stage_meta 信息
    • 接口类型:UInt(MaxMetaLength.W)

3 - BPU 全局接口

本节中介绍了香山分支预测单元整体对外交互的接口的定义,包括全局分支预测结果和单流水级预测结果的呈现形式。

BPU 模块整体对外接口 (PredirectIO)

接口定义: src/main/scala/xiangshan/frontend/BPU.scala

PredirectIO 是分支预测器整体的对外接口,它主要处理了分支预测器(BPU)与取指目标队列(FTQ)之间的交互,主要包含以下几个部分:

  • bpu_to_ftq: BPU 向 FTQ 发送的信息,主要用于 BPU 向 FTQ 发送分支预测结果
    • 接口类型: BpuToFtqIO
    • 信号列表:
      • resp: BPU 向 FTQ 发送的全局分支预测信息
        • 接口类型:DecoupledIO(new BpuToFtqBundle())
          • BpuToFtqBundle 继承自 BranchPredictionResp,没有额外的信号
        • 信号列表:详见 (BranchPredictionResp)
  • ftq_to_bpu: FTQ 向 BPU 发送的信息,主要用于处理重定向及更新请求
    • 接口类型: FtqToBpuIO
    • 信号列表:
      • redirect: FTQ 向 BPU 发送的重定向请求
        • 接口类型: Valid(new BranchPredictionRedirect)
        • 接口列表:详见(BranchPredictionRedirect
      • update: FTQ 向 BPU 发送的更新请求
        • 接口类型:Valid(new BranchPredictionUpdate)
        • 接口列表:详见(BranchPredictionUpdate
      • enq_ptr: FTQ发送给BPU的FTQ指针,告诉BPU下一次需要写到哪个FTQ表项
        • 接口类型:FtqPtr
  • ctrl: BPU 控制信号,主要用于控制各预测器的使能
    • 接口类型:BPUCtrl
    • 接口列表:
      • ubtb_enable: UBTB 预测器使能
        • 接口类型:Bool()
      • btb_enable: BTB 预测器使能
        • 接口类型:Bool()
      • bim_enable: BIM 预测器使能
        • 接口类型:Bool()
      • tage_enable: TAGE 预测器使能
        • 接口类型:Bool()
      • sc_enable: SC 预测器使能
        • 接口类型:Bool()
      • ras_enable: RAS 预测器使能
        • 接口类型:Bool()
      • loop_enable: LOOP 预测器使能
        • 接口类型:Bool()
  • reset_vector: 重置向量,reset 时 BPU 的 pc 会被重置为该值
    • 接口类型:UInt(PAddrBits.W)

全局分支预测信息 (BranchPredictionResp)

接口定义: src/main/scala/xiangshan/frontend/FrontendBundle.scala

该接口定义了分支预测器预测的所有结果信息,包含了每一阶段的预测结果,以及最后一个流水级输出的相关信息。

  • s1 s1流水级的分支预测结果
  • s2 s2流水级的分支预测结果
  • s3 s3流水级的分支预测结果
    • 接口类型:BranchPredictionBundle
    • 信号列表:详见(BranchPredictionBundle
  • last_stage_meta 最后一个流水级的输出的本轮预测的预测器元数据。是一个位向量,由每个预测器输出、并由 Composer 合并为一个。
    • 接口类型:UInt(MaxMetaLength.W)
  • last_stage_spec_info 最后一个流水级的输出的本轮预测的相关信息
    • 接口类型:Ftq_Redirect_SRAMEntry
    • 接口列表:
      • folded_hist 全局折叠历史
        • 接口类型:AllFoldedHistories(foldedGHistInfos)
      • afhob 全局分支历史最老位
        • 接口类型:AllAheadFoldedHistoryOldestBits(foldedGHistInfos)
      • lastBrNumOH 上次跳转位置。
        • 接口类型:UInt((numBr+1).W)
      • histPtr 全局分支历史指针
        • 接口类型:CGHPtr
      • ssp RAS推测栈栈顶在提交栈位置的指针
        • 接口类型:UInt(log2Up(RasSize).W)
      • sctr RAS推测栈栈顶递归计数 Counter
        • 接口类型:UInt(log2Up(RasCtrSize).W)
      • TOSW RAS推测栈(队列)写指针
        • 接口类型:CGHPtr
      • TOSR RAS推测栈(队列)读指针
        • 接口类型:CGHPtr
      • NOS RAS栈顶 Counter
        • 接口类型:CGHPtr
      • topAddr RAS栈顶返回地址
        • 接口类型:UInt(VAddrBits.W)
  • last_stage_ftb_entry 最后一个流水级的输出的FTB表项
    • 接口类型:FtqEntry
    • 接口列表:详见(FtqEntry

单流水级分支预测结果 (BranchPredictionBundle)

接口定义: src/main/scala/xiangshan/frontend/FrontendBundle.scala

该接口定义了每个流水级对外输出的分支预测结果信息,

  • pc 预测块的起始 pc
    • 接口类型:Vec(numDup, UInt(VAddrBits.W)) numDup仅为寄存器复制,其中信号完全相同
  • valid 预测结果是否有效
    • 接口类型:Vec(numDup, Bool())
  • hasRedirect 是否需要重定向
    • 接口说明:只有s2, s3阶段会重定向,重定向发生时本阶段预测结果会覆盖之前流水级的结果
    • 接口类型:Vec(numDup, Bool())
  • ftq_idx FTQ指针,指向该阶段对应预测信息的FTQ表项
    • 接口类型:new FtqPtr
  • full_pred 完整的分支预测结果
    • 接口类型:Vec(numDup, new FullBranchPrediction)
    • 接口列表:详见(FullBranchPrediction

4 - 子预测器基类与子预测器接口

本文档介绍了香山BPU中的子预测器接口,以及子预测器基类的使用,阅读此文档可帮助你了解子预测器的对外交互,和子预测器基类中信号的使用。

在香山分支预测单元中,其所有子预测器以及 Composer 的类实现都是继承自子预测器基类(BasePredictor),并且子预测器接口(BasePredictorIO)也是在子预测器基类中进行定义。因此我们可以认为,Compser 和所有子预测器都含有相同的接口。

在子预测的理解及验证当中,我们最直接的外界交互是发生在子预测器接口,以及子预测器基类中定义的一些变量,因此在子预测器的验证之前,强烈建议你阅读并理解本节文档。

子分支预测器接口的大致内容及使用方法,已在香山分支预测单元(BPU)基础设计中进行了介绍,本节文档将专注于接口的信号细节。

子分支预测器接口 (BasePredictorIO)

接口定义: src/main/scala/xiangshan/frontend/BPU.scala

每个子分支预测器都需要实现该接口,该接口定义了子分支预测器的输入输出接口。

注意:其中某些信号被定义为了 numDup 个数量,其中每个信号完全一样,多个相同信号是为其他因素考虑。

详细的信号列表如下:

  • reset_vector 重置向量,reset 时 BPU 的 pc 会被重置为该值

    • 接口类型:UInt(PAddrBits.W)
  • in BPU 向子分支预测器发送的信息

    • 接口类型:DecoupledIO(new BasePredictorInput)
    • 信号列表:
      • s0_pc s0流水级的pc
        • 接口类型:Vec(numDup, UInt(VAddrBits.W))
      • folded_hist 全局折叠历史信息
        • 接口类型:Vec(numDup, new AllFoldedHistories(foldedGHistInfos))
        • 信号列表:详见(AllFoldedHistories
      • ghist 全局分支历史信息
        • 接口类型:UInt(HistoryLength.W)
      • resp_in 全局分支预测信息(包含s1, s2, s3 预测结果信息)
        • 接口类型:BranchPredictionResp
        • 信号列表:详见(BranchPredictionResp
  • out 子分支预测器向 BPU 发送的信息(包含s1, s2, s3 预测结果信息)

    • 接口类型:new BasePredictorOutput 继承自 BranchPredictionResp
    • 信号列表:详见(BranchPredictionResp
  • ctrl BPU 子预测器使能控制信号,主要用于控制各预测器是否开启

    • 接口类型:BPUCtrl
    • 接口列表:
      • ubtb_enable: UBTB 预测器使能
        • 接口类型:Bool()
      • btb_enable: BTB 预测器使能
        • 接口类型:Bool()
      • bim_enable: BIM 预测器使能
        • 接口类型:Bool()
      • tage_enable: TAGE 预测器使能
        • 接口类型:Bool()
      • sc_enable: SC 预测器使能
        • 接口类型:Bool()
      • ras_enable: RAS 预测器使能
        • 接口类型:Bool()
      • loop_enable: LOOP 预测器使能
        • 接口类型:Bool()
  • s0_fire s0阶段握手成功信号

    • 接口类型:Vec(numDup, Bool())
  • s1_fire s1阶段握手成功信号

    • 接口类型:Vec(numDup, Bool())
  • s2_fire s2阶段握手成功信号

    • 接口类型:Vec(numDup, Bool())
  • s3_fire s3阶段握手成功信号

    • 接口类型:Vec(numDup, Bool())
  • s2_redirect s2阶段重定向信号

    • 接口类型:Vec(numDup, Bool())
  • s3_redirect s3阶段重定向信号

    • 接口类型:Vec(numDup, Bool())
  • s1_ready s1阶段是否准备好接收信息 (方向:由子预测器输出)

    • 接口类型:Bool()
  • s2_ready s2阶段是否准备好接收信息 (方向:由子预测器输出)

    • 接口类型:Bool()
  • s3_ready s3阶段是否准备好接收信息 (方向:由子预测器输出)

    • 接口类型:Bool()
  • update BPU 向子分支预测器转发的更新请求

    • 接口类型:Valid(new BranchPredictionUpdate)
    • 信号列表:详见(BranchPredictionUpdate
  • redirect BPU 向子分支预测器转发的重定向请求

    • 接口类型:Valid(new BranchPredictionRedirect)
    • 信号列表:详见(BranchPredictionRedirect

其中,流水线控制信号将会在下面内容中进行进一步的说明。

全局折叠历史 (AllFoldedHistories)

接口定义:src/main/scala/xiangshan/frontend/FrontendBundle.scala

接口类型:AllFoldedHistories(foldedGHistInfos))

全局折叠历史的接口信息仅为一个 FoldedHistory 的列表

  • hist 折叠历史列表
    • 接口类型:MixedVec(gen.map{case (l, cl) => new FoldedHistory(l, cl, numBr)})

FoldedHistory 的接口信息也仅有一项

  • folded_hist 单项折叠历史,其位宽为历史压缩后长度。
    • 接口类型:UInt(compLen.W)

也就是说,全局折叠历史接口实际上是一个存储了折叠后历史的列表,其中每一项都是一个特定长度的折叠历史。

子预测器基类

在子预测器基类中定义了若干信号,并在每个子预测器中都可以访问到,并在其中还进行了若干连线。

其中多数信号都较容易理解 ,我们需要重点关注的是其中每个流水的 pc,这还会涉及到你对于流水线控制信号的掌握。因此接下来,我们将会介绍在子预测器中需要关注的流水线控制信号的含义,以及 s1_pc, s2_pc, s3_pc 信号的含义。

其中流水线控制信号共分为 3 组:

  • fire 信号 (s0, s1, s2, s3)
  • redirect 信号 (s2, s3)
  • ready 信号 (s1, s2, s3)

子预测器基类中的 pc 信号共有四组,s0_pc_dup, s1_pc_dup, s2_pc_dup, s3_pc_dup。每组信号中有多个 pc 信号,他们完全相同,为考虑一些其他因素所复制。因此我们可单纯把他们看做 s0_pc, s1_pc, s2_pc, s3_pc

他们的用法可参照下图:

他们与流水线控制信号的关系是:

  • s0_pc 直接由输入接口中的 in.s0_pc 连接而来
  • s0_fire 生效时,下一周期 s1_pc 会输出 s0_pc 的值
  • s1_fire 生效时,下一周期 s2_pc 会输出 s1_pc 的值
  • s2_fire 生效时,下一周期 s3_pc 会输出 s2_pc 的值

也就是说,fire 信号是会影响到下一个周期的数据是否有效,比如 s0_fire 信号会影响 s1 流水的数据是否有效,s1_fire 信号会影响到 s2 流水的数据是否有效。

fire 信号是否有效取决于本流水级数据是否有效 以及 下一流水级是否 ready。例如 s1_fire 信号有效的条件必须包含 s1 阶段数据有效,以及子预测器输出的 s2_ready 信号为有效,此时便可认为,s1 阶段数据处理完成,并且 s2 阶段就绪,下一周期数据将被直接送入 s2 阶段。

因此在子预测器中,以 s1 阶段为例,s1_ready 可以阻塞数据进入 s1 阶段,当 s1_ready 生效时,下一周期 s1 阶段的数据便会生效。而 s1_fire 有效的同时,说明 s1 阶段数据已经生效,预测器也已经将 s1 阶段的结果生成,下一周期将直接被送入 s2 阶段。

redirect 信号则相对明确。以 s2 为例,当 s2_redirect 有效时,说明 s2_fire 生效的同时 s2 预测结果与上周期 s1 预测结果不同。