CPU pipeline增加了吞吐量和以及提供了更高的时钟频率,但它不是免费的,是有代价的。通过允许并行执行多个指令,CPU设计人员需要处理以下hazards:
Structural hazards Data hazards Control hazards
我们将详细讨论这些hazards,并使用MIPS 5stage pipeline进行案例研究。 Structural hazards Structural hazards是由于硬件资源有限而发生的。多个指令可能会尝试访问相同的资源集,导致冲突问题。这些资源包括register file和内存。 在同一周期中,一个指令可能处于需要register file读取访问的ID阶段,而另一个指令可能处于需要register file写入访问的WB阶段。如果register file只有一个端口,则可能会发生Structural hazards。这可以通过分配前半周期进行读取访问以及后半周期进行写入访问来解决。一个更常见的解决方案是在register file中拥有单独的读写访问端口。
在同一周期中,一个指令可能处于IF阶段,需要指令获取的内存读取访问,而另一个指令可能处于MEM阶段,需要数据存储。这可以通过分离指令存储器和数据存储器来解决。所以,在现代计算机架构中,CPU通常有一个L1指令cache和一个L1数据cache。 Data hazards 当试图访问尚未可用的数据时,就会发生Data hazards。有3种类型的Data hazards: 写后读/RAW 读后写/WAR 写后写/ WAW 在这些Data hazards中,只有RAW表示真正的数据依赖性,另外两个只是名称依赖性。在MIPS 5 stage pipeline中,写入或WB阶段总是在读取或ID阶段之后,因此在这种情况下永远不会发生WAR和WAW。 RAW hazards可能发生在以下程序中: R3 <- R1 + R2 R5 <- R3 + R4
第一个指令的结果尚未写入register file,但紧随其后的指令试图立即使用该结果。如果第二条指令试图从register file中获取值R3,其结果将不正确。 在这种情况下,一种名为“Forwarding”的技术会有所帮助。ALU可以直接将其输出提供给其输入,而不是从register file中获取值R3,这样第二条指令就可以立即使用更新的R3值。 需要记住的一点是,“Forwarding”无法解决所有RAW危险。例如: R3 <- MEM[addr]| R5 <- R3 + R4 R3要到MEM阶段结束才能使用,因此将ALU输出直接输入到其输入无助于正确执行第二指令。第二个指令需要stall一个周期,以便R3从MEM阶段Forwarding。 Control hazards 当CPU在完成条件计算之前试图为分支做出决定时,就会发生Control hazards。有几种方法可以处理Control hazards。
首先,我们可以在分支指令之后stall指令,直到条件确定。这意味着期间无法发出下一个指令。 其次,如果我们能在ID阶段而不是EX阶段解决分支,我们将只失去1个周期。这意味着ID阶段需要额外的ALU,并提前完成条件测试,以避免ID阶段和EX阶段之间的结构hazard。然而,这种方法可能会导致新的RAW危险。 请参阅下面的示例: R3 < - R1 + R2 BEZ R3 分支将在之前的指令后立即使用R3结果,R3直到EX阶段结束才可用,因此无法避免分支之前的2周期stall。 第三,在分支指令后填充stall,直到它得到解决,可以使用一种名为“delay slot”的技术。“delat slot”中的指令总是执行的,但这需要更复杂的编译器技术。编译器需要了解程序上下文,以便在不破坏程序意图的情况下填充“delay slot”。 最后,基于硬件的预测可用于投机指令执行。然而,这要求CPU具有“自我恢复”功能,以防预测不正确。
结论 显然,解决hazard最直接的解决方案是等待,但这不是首选。添加stall可能会导致性能下降,这首先违背了CPU流水线的目的。