如果添加任何阶段before检测分支的阶段(并评估条件分支的采取/不采取),1 个延迟槽不再隐藏进入管道第一阶段的分支与正确的程序计数器地址之间的“延迟”after分支已知。
第一个获取阶段需要管道中稍后的信息来知道下一步要获取什么,因为它不itself检测分支。例如,在具有分支预测的超标量 CPU 中,它们需要在解码后预测分支的走向,从而单独且更早地预测下一个要获取的指令块。
1 个延迟槽仅在 MIPS I 中足够,因为分支条件是在上半场EX 中的一个时钟周期 https://stackoverflow.com/questions/56586551/how-does-mips-i-handle-branching-on-the-previous-alu-instruction-without-stallin/58601958#58601958,及时转发到 IF 的第二半,在此之前不需要获取地址。 (原始 MIPS 是经典的 5 级 RISC:IF ID EX MEM WB。)参见维基百科关于经典 RISC 流水线的文章 https://en.wikipedia.org/wiki/Classic_RISC_pipeline有关更多详细信息,特别是控制危险部分 https://en.wikipedia.org/wiki/Classic_RISC_pipeline#Control_hazards.
这就是为什么 MIPS 仅限于简单的条件,例如beq
(通过 XOR 查找任何不匹配项),或者bltz
(符号位检查)。它不能做任何需要加法器进行进位传播的事情(因此一般blt
两个寄存器之间是只是一条伪指令 https://stackoverflow.com/questions/19923977/why-isnt-mips-blt-instruction-implemented-in-hardware).
这是非常严格的:较长的前端可以吸收较大/关联性更强的 L1 指令缓存的延迟,该缓存需要超过半个周期才能响应命中。 (MIPS 我解码的是very不过很简单,由于指令格式是有意设计的,因此机器代码位可以直接连接为内部控制信号。因此,您也许可以在“半周期”阶段进行解码,获取 1 个完整周期,但即使 1 个周期仍然很低,在更高的时钟速度下周期时间更短。)
提高时钟速度可能需要添加另一个读取阶段。解码必须检测数据危险并设置旁路转发;最初的 MIPS 通过不检测加载使用危险来简化这一过程,相反,软件必须尊重加载延迟槽,直到 MIPS II。即使有 1 个周期的 ALU 延迟,超标量 CPU 也可能存在更多危险,因此检测必须转发的内容需要更复杂的逻辑,以将旧指令中的目标寄存器与较新指令中的源进行匹配。
超标量管道甚至可能需要在指令获取中进行一些缓冲以避免气泡。多端口寄存器文件的读取速度可能会稍慢,可能需要额外的解码流水线阶段,尽管这可能仍然可以在 1 个周期内完成。
因此,除了由于超标量执行的本质而导致 1 个分支延迟槽不足之外,如果额外的阶段位于提取和分支解析之间,较长的管道也会增加分支延迟。例如一个额外的获取阶段和一个 2 宽的管道可以在分支后有 4 条正在运行的指令而不是 1。
但不是引入更多的分支延迟slots要隐藏这个分支延迟,实际的解决方案是分支预言。 (然而,一些 DSP 或高性能微控制器确实有 2 个甚至 3 个分支延迟槽。)
分支延迟槽使异常处理变得复杂;你需要一个错误返回and下一个地址,以防故障出现在所采用分支的延迟槽中。