第一张图没有传递机制
竞争情况分析
-
读后写(RAW)竞争:当某条指令需要读取一个寄存器的值,而该寄存器的值尚未被前面的指令写入时,就会发生这种竞争。
- 指令2(
dadd r1, r1, r3
)依赖于指令1(dadd r1, r1, r2
)的结果,因为它也需要使用寄存器r1
。但是此时指令1还未完成写回(WB)阶段。 - 指令3(
dadd r1, r1, r4
)同样依赖于指令2的结果,因此也存在RAW竞争。
- 指令2(
-
流水线暂停(Stalls):为了处理这些数据竞争,流水线引入了暂停(即指令2和指令3中空白的部分)。这些暂停使得指令可以延迟执行,等待前面的指令写回所需的数据。
第二张图有传递机制
在流水线处理器中,前递(Forwarding),也叫数据转发,是一种解决数据冒险的技术。它通过在指令执行的不同阶段之间直接传递数据来消除依赖,而不是等待指令写回(WB)阶段完成。这样可以减少流水线的暂停(Stall),提高执行效率。
如何用前递解决数据冒险
在图中的例子里,我们有以下指令:
dadd r1, r1, r2
dadd r1, r1, r3
dadd r1, r1, r4
这些指令之间存在**读后写(RAW)**冒险,例如指令2依赖于指令1的结果,指令3依赖于指令2的结果。
解决步骤:
-
检测数据依赖:流水线需要检测指令之间的数据依赖关系。例如,当指令2在ID(指令译码)阶段时,它会检查寄存器
r1
的值是否已经被上一条指令(即指令1)修改。 -
前递实现:在不使用前递的情况下,指令2必须等到指令1完成WB阶段后才能读取
r1
的值。但是通过前递技术,处理器可以在指令1的EX(执行)阶段完成计算后,直接将结果发送到指令2的EX阶段,而不是等待WB阶段。- 在这种情况下,指令1的执行结果会被直接前递给指令2的EX阶段。
- 类似地,指令2在EX阶段的结果会前递给指令3的EX阶段。
-
减少Stall:通过前递,流水线可以消除许多数据依赖引起的暂停。例如,指令2和指令3不再需要等到前面指令完全写回后才能进行EX阶段的计算。
示例流程(按图中的例子)
假设我们在流水线中实现了前递,那么可以按以下方式执行:
- 指令1 (
dadd r1, r1, r2
) 在 EX 阶段计算完结果。 - 在指令1的 EX 阶段结束时,直接将结果前递给指令2的 EX 阶段,这样指令2无需等待。
- 同理,指令2的 EX 阶段结束后,将其结果前递给指令3的 EX 阶段。
在这样的操作下,指令2和指令3不需要等待寄存器的写回过程,而是直接获取前一条指令的执行结果。
总结
- 前递通过在流水线的执行阶段直接传递数据,消除了指令间的数据依赖。
- 在前递的帮助下,流水线可以减少或完全避免Stall,从而提高执行效率。
- 前递通常是在硬件中实现的,通过额外的逻辑单元来检查和转发数据。
这样,通过前递技术,可以在流水线结构中更有效地解决数据冒险问题。
- 代码来自 从零开始写riscv处理器(五)数据冒险:停顿与前递