addiu $6,$6,5
bltz $6,$L5
nop
...
$L5:
这怎么安全而不会出现停顿,即使是经典的MIPS也只有在缓存未命中时才能做到,原始的MIPS指的是没有互锁流水线级别的微处理器,并且拥有一个负载延迟槽而非互锁。
原始的MIPS I是一种经典的5级RISC IF ID EX MEM WB
设计,通过单个分支延迟槽在ID阶段尽早检查分支条件来隐藏所有分支延迟(更正:这是错误的,请阅读本答案;不要被此错误前提下的其他细节所误导)。这就是为什么它受限于等于/不等于,或者像小于零或大于等于零这样的标志位检查,而不是需要通过加法器进行进位传递的两个寄存器之间的小于检查。
这难道不意味着分支需要比ALU指令提前一个周期准备好输入吗?bltz
与addiu
同时进入ID阶段。
addu
/xor
)具有单周期延迟,并且可以在连续周期内运行。
MIPS代表“没有交错流水线级别的微处理器”,因此它不会检测RAW风险;代码必须避免它们。(因此第一代MIPS上有负载延迟槽,MIPS II添加了交错以在这种情况下停顿,使首字母缩写无效:P)。
但我从未看到有关计算分支条件多个指令的讨论,以避免停顿。(addiu/bltz示例是由MIPS gcc5.4发出的
-O3 -march=mips1
on Godbolt,它会尊重加载延迟槽,如有需要则填充nop
。)
它是否使用了某种技巧,例如EX在时钟下降沿读取输入,而ID不需要转发的寄存器值直到上升沿?(前提是EX产生的结果足够早以使其起作用)
我猜如果时钟速度足够低以使缓存访问为单周期,则这将是有意义的。
MIPS中的停顿或气泡声称lw
+对加载结果的beq
需要2个停顿周期,因为它无法转发。但实际的MIPS I并非如此(除非gcc存在漏洞)。 它确实提到了半个时钟周期,允许在同一个完整周期内写入并从寄存器文件中读取一个值。
bltz
进入ID
以及addiu
进入EX
时,它们有整整一个时钟周期来稳定其输出并将结果写入中间级联寄存器。所以EX
只需直接转发这些寄存器,而ID
最初使用旧值,但新值及时到达,使其值通过ID
条件检查门展开。基本上,就像你所说的,这可能实际上是一种组合逻辑(而不是基于时钟的)而不是顺序网络(这将使其成为“流水线” ID 阶段)。 - Margaret Bloom