【《硬件架构的艺术》读书笔记】06 流水线的艺术(3)
6.9 流水线冒险
冒险会干扰流水线并阻止下一条指令在目标时钟周期内的执行。冒险会降低流水线在理想情况下所能带来的速度提升。
冒险分类:
1、结构冒险:资源冲突导致硬件无法支持所有可能的指令组合同时执行。
2、数据冒险:指令执行需要之前指令计算结果,而这个结果还在流水线中没计算出来。
3、控制冒险:分支的流水线的其他指令改变程序计数器的值。
通用方法:停止流水线直至风险消除,在流水线中插入多个“气泡”。
6.9.1 结构冒险
如图,MEM在一个周期内被两个指令使用,产生冲突。
解决方法:如图,停一个周期,待对MEM的冲突解除后再恢复流水线。
另一种方法:IF和MEM阶段使用不同的存储器来避免同时访问同一块存储器。缺点:消耗更多资源。
6.9.2 数据冒险
对于下面指令:
如图,ADD之后的指令无法得到正确的执行结果,因为后续指令的ID阶段都需要ADD指令的结果。
解决方法:数据/寄存器转移。大概意思就是把第一个指令的ALU寄存后直接输出到下一级ALU的输入。对于两个、三个周期后的指令,则需要把MEM输出、REG输出直接连接到后续流水线。
对于下面指令:
如图6.20,路径1永远无法实现,因为XOR指令需要在ALU输入端使用R1寄存器的值,该值在LW指令执行后才能更新。
简单的方法:使用纵向旗袍,将ALU周期延一个时钟。
除了使用硬件技术,也可以使用基于编译器调度的软件方式来解决数据冒险的问题。这时,编译器跟踪每个寄存器中的数据,并重新安排指令次序阻止数据冒险的产生。
6.9.3 控制冒险
如下指令:
T2在执行第二条指令时就需要PC值,但是该值要在第二条指令的MEM操作后才可能。
解决方法:分支语句中用新的PC值重新获取下一条指令。这种情况下,需要将流水线停止几个周期,直到重新获取下一条指令。如图:
6.9.4 其他风险
指令获取或在数据读写时会访问存储器,指令获取时,数据应该由PC寄存器保持稳定。该值应该一直保持到把获取的指令写入IF/ID流水线寄存器的IR域为止。因此,对IF/ID寄存器的IR操作必须在PC写操作之前。
数据读写时,有效地址在EX阶段由ALU计算得到。在将存储器中的数据存入LMD寄存器或存储器写信号被激活使数据写入存储器之前,该地址不能变化。
6.10 ADC流水线——一个例子
该ADC有四级流水线,每级流水线提供三位数字量,所以一共是12位ADC。每级流水线采样并得到差值传递到下一级,提高了ADC的处理能力。