BPU 子模块 ITTAGE
功能
ITTAGE 接收来自 BPU 内部的预测请求,其内部由一个基预测表和多个历史表组成,每个表项中都有一个用于存储间接跳转指令目标地址的字段。基预测表用 PC 索引,而历史表用 PC 和一定长度的分支历史折叠后的结果异或索引,不同历史表使用的分支历史长度不同。在预测时,还会用 PC 和每个历史表对应的分支历史的另一种折叠结果异或计算 tag,与表中读出的 tag 进行匹配,如果匹配成功则该表命中。最终的结果取决于命中的历史长度最长的预测表的结果。最终,ITTAGE 将预测结果输出至 composer。
间接跳转指令的预测
ITTAGE 用于预测间接跳转指令。普通分支指令和无条件跳转指令的跳转目标直接编码于指令中,便于预测,而间接跳转指令的跳转地址来自运行时可变的寄存器,从而有多种可能选择,需要根据分支历史对其作出预测。
为此,ITTAGE 的每个表项在 TAGE 表项的基础上加入了所预测的跳转地址项,最后输出结果为选出的命中预测跳转地址而非选出的跳转方向。
由于每个 FTB 项仅存储至多一条间接跳转指令信息,ITTAGE 预测器每周期也最多预测一条间接跳转指令的目标地址。
香山昆明湖 V2R2 架构中的 ITTAGE 提供了 5 个带 tag 的预测表 T1-T5,基准预测器和带 tag 的预测表的基本信息见下表。
| 预测器 | 是否带 tag | 作用 | 表项构成 | 项数 |
|---|---|---|---|---|
| 基准预测器 T0 | 否 | 用于在带 tag 预测表的 tag 均不匹配时提供预测结果 | ITTAGE 中并没有实现 T0,而是直接使用 ftb 的预测结果作为基准预测结果 | |
| 预测表 T1-T5 | 是 | 存在 tag 匹配时,选历史长度最长者提供预测结果 | valid: 1bit; tag: 9bit; sctr: 2bits(表示要不要输出这个预测结果); useful: 1bit(usefulness 计数器); target_offset: 20 bits(target 共 50 bits,出于面积考虑,高位 30 bits 分开存储) | T1-T2 各 256 项,T3-T5 各 512 项 |
在 BPU 模块中维护了一个 256 比特的全局分支历史 ghv,并为 ITTAGE 的 5 个带 tag 的预测表分别维护了各自的折叠分支历史,折叠算法同 TAGE 。折叠历史具体配置见下表,其中 ghv 是一个循环队列,"低"n 位指的是从 ptr 指示的位置算起的低位:
| 历史 | index 折叠分支历史长度 | tag 折叠分支历史 1 长度 | tag 折叠分支历史 2 长度 | 设计原理 |
|---|---|---|---|---|
| 全局分支历史 ghv | 256 比特 | 无 | 无 | 每比特代表对应分支跳转与否 |
| T1 对应折叠分支历史 | 4 比特 | 4 比特 | 4 比特 | ghv 取 ptr 起低 4 比特折叠异或 |
| T2 对应折叠分支历史 | 8 比特 | 8 比特 | 8 比特 | ghv 取 ptr 起低 8 比特折叠异或 |
| T3 对应折叠分支历史 | 9 比特 | 9 比特 | 8 比特 | ghv 取 ptr 起低 13 比特折叠异或 |
| T4 对应折叠分支历史 | 9 比特 | 9 比特 | 8 比特 | ghv 取 ptr 起低 16 比特折叠异或 |
| T5 对应折叠分支历史 | 9 比特 | 9 比特 | 8 比特 | ghv 取 ptr 起低 32 比特折叠异或 |
ITTAGE 需要 3 拍延迟:
- 0 拍生成寻址 index
- 1 拍读出数据
- 2 拍选出命中结果
- 3 拍输出
写缓存(WriteBuffer)
每个 IttageTable 使用 WriteBuffer 模块实现写缓存,用于在 SRAM 写操作与读操作冲突时,暂存写请求以保证数据一致性。 每次 ITTAGE 更新时都会写进这个 WriteBuffer;当 SRAM 读端口空闲时,WriteBuffer 会将数据写入 SRAM。
预测器训练
首先,定义所有产生 tag 匹配的预测表中所需历史长度最长者为 provider,而其余匹配的预测表(若存在的话)被称为 altpred。 当 provider 的 ctr 为 0 时,会选择 altpred 的结果作为预测结果。
ITTAGE 表项中包含一个 usefulness 域,当 provider 预测正确而 altpred 预测错误时 provider 的 usefulness 置 1,表示该项是一个有用的项,便不会被训练时的分配算法当作空项分配出去。当 provider 产生的预测被证实为一个正确的预测,且此时的 provider 与 altpred 的预测结果不同,则 provider 的 usefulness 域被置 1。
若预测地址与实际一致,则将对应 provider 表项的 ctr 计数器自增 1;若预测地址与实际不一致,则将对应 provider 表项的 ctr 计数器自减 1。ITTAGE 中,会根据 ctr 判断是否采取这个预测的跳转目标结果。当 ctr 为 0 时,会选择 altpred 的结果。
接下来,若该 provider 所源自的预测表并非所需历史长度最高的预测表,则此时执行如下的表项增添操作。表项增添操作会首先读取所有历史长度长于 provider 的预测表的 usefulness 域。若此时有某表的 usefulness 域值为 0,则在该表中分配一对应的表项;若没有找到满足 usefulness 域值为 0 的表,则分配失败。当有多个预测表(如 Tj,Tk 两项)的 usefulness 域均为 0 时,表项的分配概率是随机的,分配的时候随机把某些 table 给 mask 掉,让它不会每次都分配同一个。这里的表项分配的随机性是通过 chisel 的 util 包里的 64 位线性反馈移位寄存器原语 LFSR64 生成伪随机数来实现的,在 verilog 代码中对应 allocLFSR_lfsr 寄存器。在训练时,用 8 位饱和计数器 tickCtr 统计分配失败次数-成功次数,当分配失败的次数足够多,tickCtr 计数器计数到满达到饱和时,触发全局 useful bit reset,把所有的 usefulness 域清零。
注:ITTAGE 的清零 usefulness 域的饱和计数器名字是 tickCtr,长度为 8 比特,名字和长度均与 TAGE 不同。
最后,在 ITTAGE 表分配新项时,新表项中的 ctr 计数器均被设置为 2,usefulness 域被设置为 0。
存储结构
- 5 张历史表,项数分别为 256、256、512、512、512,每张表没有分 bank。
- 每个表项含有 1bit valid,9bit tag,2bit ctr,20bit target_offset,1bit useful,都使用 SRAM 统一存储。
- 以 FTB 结果作为 base table。
- 每个历史表有 4 项的写缓存(WriteBuffer)。
预测流程
- s0 进行索引计算,地址送入 SRAM
- s1 读出表项,进行 bank 选取,以及判断是否命中,结果寄存到 s2
- s2 计算最长历史匹配和次长历史匹配:
- 当存在历史表命中,且 ctr!=0 的时候,尝试使用最长历史结果目标地址
- 当 provider 信心不足(ctr==0)时,若次长历史命中,尝试使用次长历史结果目标地址
- 当没有历史表命中的时候,使用 FTB 结果
- s3 使用目标地址,在 BPU 内和 s2 结果进行比对,判断是否需要冲刷流水线
训练流程
基本和 TAGE 相同,对于 target 字段,仅当分配新表项或者原 ctr 为最小值 0 时,才会替换新值,否则保持原样。