流水线是一条能够使多条指令重叠执行的实现技术。
1 取指
2 译码
3 执行操作或计算地址
4 访存(如有必要)
5 写回(如有必要)
单周期实现与流水线性能
ld双字载入,sd双字存储。add sub and or beq
在理想条件下和有大量指令情况下,流水线带来的加速比约等于流水线级数。五级流水线带来的加速比接近5.
流水线冒险
结构冒险
硬件不支持多条指令在同一时钟周期执行。
因缺乏硬件支持而导致指令不能在预定的时钟周期内执行的情况。
RISCV指令系统面向流水线设计,很容易避免结构冒险。
流水线有两个存储器,就不会发生第一条指令在存储器取数据的同时第四条指令从同一存储器取指令,流水线就不会发生结构冒险。
数据冒险
由于一个步骤必须等待另一个步骤完成而导致的流水线停顿叫做数据冒险。
在计算机流水线中,数据冒险源于一条指令依赖于前面一条尚在流水线中的指令。
一种解决方法是,不需要去等待指令完成就可以尝试解决数据冒险。 一旦ALU计算出加法的和,就可将其作为减法的输入。 向内部资源添加额外的硬件以尽快找到缺少的运算项的方法。称为前递或旁路。
前递或旁路: 一种解决数据冒险的方法,提前从内部缓冲中取到数据,而不是等数据到达程序员可见的寄存器或存储器。
前递
仅当目标阶段在时间上晚于源阶段,前递的路径才有效。例如,从第一套指令存储器的访存阶段的输出到下一条指令执行阶段的输入不可能存在有效前递路径。否则意味着时间倒流。
前递的效果很好,但不能避免所有流水席的停顿。假如,第一条指令是load x1而不是加法指令,在第一条指令的第四个阶段之后,sub指令所需的数据才可用,这对于sub指令第三个阶段的输入来说太迟了。 因此即使使用前递,流水线也不得不停顿一个阶段来处理载入 -- 使用型数据冒险。
载入-- 使用型冒险: 一种特定形式的数据冒险,指当载入指令要取的数据还没取回时,其他指令就需要该数据的情况。
流水线停顿 ---也称为气泡。为了解决冒险而实施的一种阻塞。
流水线停顿: 使用硬件检测和停顿。 或由软件对代码重新排序以尽量避免载入--使用型流水线停顿。
当一条load指令之后紧跟一条使用其结果的R型指令,即使使用前递也需要停顿。如果不停顿,从存储器访问阶段的输出到执行阶段的输入这条路径意味着时间倒流。这是不可能的。
可以重排c语言代码避免流水线停顿
控制冒险
当需要根据一条指令的结果做出决定,而其他指令正在执行。
控制冒险:也称为分支冒险,由于取到的指令并不是所需要的,或者指令地址的流向不是流水线所预期的,导致正确的指令无法在正确的时钟周期内执行。
条件分支指令。在取出分支指令后,紧跟着下一个时钟周期取出下一条指令,但是流水线不知道下一条指令应该是什么,因为它刚从存储器取出分支指令。假设足够多的硬件资源,在流水线第二个阶段测试寄存器,计算分支目标地址和更新PC。通过这些硬件资源。 如果分支指令不成立,要执行的指令在开始执行之前需额外等待停顿一个时钟周期。
每遇到条件分支指令就停顿以避免控制的流水线
对于较长的流水线,通常无法在第二阶段解决分支指令的问题。
解决控制冒险的第二个方法。预测不发生或者采用分支预测
预测来处理条件分支,简单的方法时总是预测条件分支指令不发生。如果预测正确,流水线全速前进。流水线分支跳转时,流水线才停顿。
更成熟的分支预测是 预测一些条件指令发生跳转,而另一些不发生跳转。---静态预测
还有动态预测,保存每个条件分支的历史记录,根据最近的过去行为来预测未来。
控制冒险的第三种解决方法是延迟决定。 延迟转移顺序执行下一条指令,在该指令后执行分支。
总结
流水线 --- 顺序指令流中开发指令间并行性的技术。