流水线冒险
回顾一下常用五阶段流水线:F(取指)D(译码)E(执行)M(访存)W(写回)
注意:对寄存器文件的写只有在时钟上升的时候才会更新!
数据冒险的原因:对寄存器文件的读写是在不同阶段进行的
1.用暂停来避免数据冒险
暂停时,处理器会停止流水线中一条或多条指令,直到冒险条件不再满足。
在本该正常处理的某指令阶段中,我们每次要把一条指令阻塞在译码阶段,就在执行阶段插入一个气泡。
实现简单,但性能不好,严重降低了整体的吞吐量
2.用转发来避免数据冒险
①译码阶段逻辑发现寄存器是操作数的源寄存器,但是在写端口上还有一个对该寄存器未进行的写,将结果值直接从一个流水线阶段传到较早阶段的技术称为数据转发(旁路)。这种情况的信号是W_valE。
②访存阶段中有对寄存器未进行的写,也可以用数据转发。这种情况的信号是m_valE。
③执行阶段ALU正在计算的值稍后会写入寄存器时,也可以将ALU的输出信号作为操作数valB,这种情况的信号是e_valM。
④可转发刚从内存中读出的值,这种情况的信号是m_valM。
⑤可转发写回阶段对端口M未进行的写,这种情况的信号是W_valM。
3.加载/使用数据冒险
有一类数据冒险不能单纯用转发来解决,因为内存读在流水线发生的比较晚,这时我们可以通过将暂停和转发结合起来,避免加载/使用数据冒险。
这种用暂停来处理加载/使用冒险的方法称为加载互锁,加载互锁和转发技术结合起来,足以处理所有可能类型的数据冒险
4.避免控制冒险
当处理器无法根据处于取值阶段的当前指令来确定下一条指令的地址时,就会出现控制冒险(在流水线化处理器中,控制冒险只会发生在ret指令和跳转指令)跳转指令只有在条件跳转方向预测错误时才会造成麻烦。
ret指令经过译码,执行和访存阶段时,流水线不能做任何有用的活动,我们只能在流水线中插入三个气泡,一旦ret指令到达写回阶段,PC选择逻辑就会将程序计数器设为返回地址。
跳转指令的执行阶段才会知道是否应该跳转,但在这之前流水线预测会选择分支并取指、译码、执行,当跳转指令通过执行阶段后,流水线会向译码阶段和执行阶段插入气泡,取消两条目标指令,同时取出跳转指令后面的那条指令,
缺点:两个时钟周期的指令处理能力是被浪费的。
通过慎重考虑流水线的控制逻辑,控制冒险是可以被处理的,暂停和往流水线中插入气泡的技术可以动态调整流水线的流程。