香山分支预测单元基础

本节介绍了香山分支预测单元(BPU)的基础思想和工作原理,包括采用的分支预测块思想、多预测器、多流水线结构以及取指目标队列(FTQ)的作用,说明了 BPU 对外交互的主要接口。

分支预测块思想

对于一般的分支预测器来说,通常会根据给定的 PC 预测出该 PC 所对应的指令的相关信息,如是否是条件分支指令、是否是跳转指令。对于条件分支指令,会预测出是否会跳转,而对于跳转指令,则会预测出跳转目标。然而,这种一条一条地预测指令的方法效率较低,导致前端指令供给过慢。

相比之下,香山采用的预测方法是每次预测一个指令块。也就是说,给定一个 PC,香山会预测出以这个PC开始的一个分支预测块,包括了接下来若干条指令的情况,如是否存在分支指令、分支指令的位置、是否跳转以及跳转目标等信息

这样的预测方法可以一次性地预测出多条指令,并将预测结果送往取指单元(IFU),指导IFU进行取指。此外,由于IFU需要考虑缓存行的性能问题,它可以根据预测块一次性地取出多条指令,从而提高吞吐效率。

在预测块产生后,分支预测块还会生成执行完本预测块后跳转到的 PC,接着 BPU 会根据该 PC 继续产生下一个分支预测块

举个简单的例子

如上图所示,当 PC 执行到 0x20000118 时,BPU会经历如下几个步骤:

  1. BPU得知PC 0x20000118
  2. BPU产生以 0x20000118 为开始的分支预测块,内容大致如下
    1. 在接下来的若干条指令中
    2. 第三条是一个条件分支指令
    3. 对于这个条件分支指令,预测他将会跳转
    4. 跳转后的地址为 0x20000110
  3. BPU将PC设置为 0x20000110,并继续产生下一个分支预测块

这便是采用了分支预测块的香山 BPU 的基本预测流程

多预测器、多流水线结构

上图展示了香山BPU的总体架构,其中我们需要关注两个主要方面:

多预测器

  1. 为了确保预测的准确性,香山 BPU 采用了多个预测器,并且这些预测器共同产生 BPU 的预测结果。例如,FTB 会生成基础的预测结果供后续预测器使用,而 TAGE 则对条件分支指令产生更精准的预测结果等。

多流水线

  1. 为了满足高性能的需求,香山 BPU 采用了流水线设计。各个预测器处于不同的流水线级别。其中,uFTB(即图中的uBTB)预测器位于第一流水线级别,能够在一个周期内产生预测结果。而其余预测器则需要2-3个周期才能生成预测结果,尽管预测时间较长,但预测结果相对更精确。

但是,如果在第三个周期才能获取到预测结果,并基于新的结果重新开始预测,这样的设计难免导致性能损失。因为这样一来,需要耗费三个时钟周期才可以完成一次预测。

为了在第一和第二周期就能够获取到某些预测器的预测结果,我们设置了三个预测结果通道,并将三个流水线级别的预测结果同时输出,如下图所示。

取指目标队列(FTQ)

分支预测结果暂存

尽管 BPU 可以以分支预测块的形式提供预测结果,IFU 也可以一次性取指多条指令,但它们之间仍然存在性能上的差距。通常情况下,BPU产生预测结果的速度更快。

因此,在 BPU 与 IFU 之间添加了一个取指目标队列(FTQ)作为缓冲。FTQ 本质上是一个队列,用于存储一个个数据项。BPU产生的预测结果会先暂存到FTQ中,然后由 IFU 从 FTQ 中获取预测结果,如下图所示。

每当 BPU 产生一个预测块,该预测块会被放入 FTQ 的队首。当 IFU 处于空闲状态时,它会从 FTQ 队尾获取下一个预测块。下方的示意图展示了这一过程。

在香山中,FTQ 的功能远远不止于此。参考上文图中 FTQ 的对外交互接口,可以看出它还负责向 ICache 发送预取信息,存储 BPU 的各类训练信息,负责分析取指模块、后端执行模块中发来的重定向信息、更新信息,还会向 BPU 发送更新请求,甚至 FTB 预测器中的基本数据结构——FTB项都是由 FTQ 来更新的。

BPU 预测结果重定向

上文中提到,香山分支预测结果共有三个通道,会同时输出 s1, s2, s3 流水级的预测结果,那 FTQ 如何使用三个阶段的预测结果呢?

我们不妨从探讨流水线的时序出发,如下图所示

  • 在第一个周期,一个新的PC 0x4 被送入,能在一周期内产生预测结果的预测器(叫做 uFTB)在 s1 接口输出了他的预测结果,并且结果指示下一个 PC 为 0xf,其他接口还无输出
  • 在第二周期,PC 被设置为了 0xf,而 uFTB 也产生了 0xf 的预测结果,并从 s1 通道送出。与此同时,两周期预测器产生了上一轮 0x4 地址的预测结果,并从 s2 通道送出。

那么在这里产生了一个问题,第二周期 s2 产生的是 0x4 预测结果,而 0x4 的预测结果已经在上一周期被 s1 所输出,并放置在了 FTQ 中的某个项中。也就是说 s2 产生的预测结果,已经在 s1 通道被产生过了。但不同点是 s2 结果是由两周期预测器产生而来,结果会更加准确。

因此我们需要做的并不是根据 s2 的预测结果,放置一个新的 FTQ 项,而是 对比 s2 预测结果和上一周期 s1 预测结果是否有差异,如果有差异则覆盖上一阶段 s1 接口放置的 FTQ 项

于是我们给 s2 和 s3 通道增加两个额外的信号线,我们称之为 redirect 信号,如果该信号有效说明此时该阶段的预测结果与之前的预测结果产生差异,并且需要覆盖之前某个位置的 FTQ 项。结构如下图所示。

结构示意图中的时刻,对应流水线的第二个周期,此时 s1 通道已经往 FTQ 中放入一个地址为 0x4 的分支预测块结果,而此时 s2 预测结果产生,BPU 发现 s2 预测结果与 s1 不同,则本周期 redirect 接口被置为有效。FTQ 会使用 s2 通道的预测结果覆盖之前存放 0x4 预测结果的 FTQ 项。

此时,s1 通道虽然也产生了以 0xf 为首的分支预测块,但显然,0xf 是 s1 基于第一周期的错误预测结果产生的 PC,因此在这时候,s1 结果可直接弃之不用。

在第三周期,s1 又使用 s2 所产生的正确预测结果所指示的新PC 0x8 开始了新一轮预测。之后,如果 s2, s3 通道始终未检测到有预测错误发生,则流水线将以满状态持续运行下去。

BPU 重定向请求

无论再精确的分支预测器也不总是正确的,这种不正确会导致后续流水线中填充错误的指令,因此需要有一种机制来纠正这种错误,这种机制就是重定向。指令在被后端执行模块执行时,这条指令真正的行为才会被确定,因此在这个时候,后端执行模块如果发现分支预测错误,就会发出 重定向请求 (注意此处重定向请求与上文预测结果重定向是不同的概念),让处理器的状态恢复到执行错误指令之前的状态,对于我们来说,只需要关注BPU和FTQ在重定向时是怎样恢复状态的即可。

除了后端会产生重定向请求,香山处理器中会在 IFU 取到指令之后对指令进行简单分析,检测出最基本的预测错误。具体的过程是这样的,FTQ 向 IFU 发送取指请求之后,会等待 IFU 返回预译码信息(预译码是IFU对指令的简单解码,例如是否是跳转指令、跳转的目标是什么),FTQ 会将预译码信息写回到对应 FTQ项 中的某个字段,同时会分析预译码信息,如果发现预测错误,便会生成一个 IFU 重定向请求。

来自后端执行模块的重定向请求不需要 FTQ 生成,是直接由后端发往 FTQ 进行处理。FTQ 会将生成的 IFU 重定向请求与后端重定向请求转发到 BPU 的重定向接口中去,如果二者在同一周期有效,那么FTQ会选择转发后端重定向请求。

添加了重定向接口的 BPU 如下图所示。

BPU 的更新请求

目前的 BPU 已经有了纠错的能力,但是还有一个问题,BPU 中的数据没有办法得到更新。如果无法获取指令的位置、类型、是否发生跳转以及跳转地址等信息,BPU 将得不到训练,并导致准确度大幅降低。

为了获得这些信息,我们仍需依赖于取指目标队列(FTQ),因为它不仅能与 IFU 交互获取指令相关的信息,还可以与后端交互,获取执行的相关信息。 因此会有一个更新请求通道由 FTQ 直接连接至 BPU。

当后端执行完 FTQ 中的某一项时,该项会被标识为已提交,接下来 FTQ 将该项的更新信息,通过 Update 通道发往BPU。

总结

通过本节,我们了解到 BPU 对外交互所需的所有主要接口,以及 FTQ 对于 BPU 的作用。拥有了预测结果接口、重定向接口、更新接口的 BPU已经可以支撑 BPU 的所有对外交互了。接下来我们会将目光深入 BPU 内部。

最后修改 October 27, 2024: Fix typo (e95831c)