分支恢复
分支预测的结果和执行的结果一致是我们所希望的, 但也总有预测失败的情况. 当分支预测失败的时候, 我们需要恢复处理器核心到这条预测失败的分支之前, 该过程称为 分支恢复 .
对于分支恢复的处理, 同样决定了处理器的性能, 分支恢复的处理决定了分支恢复的时间惩罚(Penalty), 即浪费了多少个周期在错误的路径上, 以及需要多少个周期从错误的路径恢复到正确的路径.
Bergamot 中的分支恢复
在 Bergamot 存在状态的部件总共有两种:
- 流水线
- 表结构
分支恢复仅对这两种部件进行分支恢复. Bergamot 采用全恢复策略, 即恢复之后, 核心内没有一条有效的指令, 核心等待新路径上的指令重新填充流水线. 有些高性能处理器采用半恢复策略, 即恢复之后核心存在有效的指令继续执行.
当分支恢复进行时, 核心中 recover
信号组被拉高, 表示核心进入恢复周期.
流水线分支恢复
Bergamot 的一般流水线中的数据存放在 inReg
采样寄存器中, 其中有 valid
位记录当前数据是否有效.
若流水线检测到 recover
信号被拉高, 说明当前处理的数据 inReg
都是无效的数据, 需要丢弃, 在一个周期内, 将 inReg
中的 valid
置 false
即可完成恢复.
例如在 ALU 流水线中, 解码阶段的实现:
src/main/scala/bergamot/core/execute/ALU.scala
class ALUDecodeStage extends Module {
val io = IO(new Bundle {
// Pipeline interface
val in = Flipped(DecoupledIO(new ExecuteEntry()))
val out = DecoupledIO(new ALUExecuteStageEntry())
// CSR read interface
val csr = Flipped(new CSRsReadIO())
// Current core privilege
val privilege = Input(PrivilegeType())
// Recovery interface
val recover = Input(Bool())
})
// Pipeline logic
private val inReg = RegInit(new ExecuteEntry().zero)
when(io.out.fire) { // Stall
inReg.valid := false.B
}
when(io.in.fire) { // Sample
inReg := io.in.bits
}
io.in.ready := io.out.ready
// Combinational logic
// ...
// ...
// Recovery logic
when(io.recover) {
inReg.valid := false.B
}
}
在最后几行中 when(io.recover)
判断 recover
信号, inReg.valid := false.B
丢弃流水线中的数据.
之后只需要等待正确路径上的数据进入流水线即可.