RiscV转发,我们为什么不需要呢?

问题描述

谁能帮我理解为什么在第 1 行和第 3 行之间我们不需要转发(1 和 2 之间没有绿色箭头)

我认为我们需要它,因为 sub 使用 add 确定的 t0 值,并且两者都在同时对该值进行读取和写入。(准确地说,当时钟上升时,add 的写入发生得更晚)

解决方法

您是对的,在第三条指令 (sub) 中,在解码阶段已经读取了不正确(例如过时)的值,因此需要采取诸如转发之类的缓解措施。

实际上,该 sub 指令读取了两个不正确(陈旧)的值,一个用于第一个操作数 t0,另一个用于第二个操作数 t3,作为该寄存器由紧接在前的指令更新。

第一个实际寄存器更新(t0add)在周期 5(基于 1 的计数)可用,但 sub 的解码发生在周期 4。A forward 是必需的:这里可以从 add 的 W 阶段到 sub 的 ALU 阶段 - 或者 - 可以从 add 的 M 阶段到sub 的 D 阶段。

只有在(第 4 条指令,未显示)之后的下一个周期中,解码才能从较早指令的 W 阶段获得正确的最新值——如果 W 阶段与后续指令的 D 阶段重叠,则没有转发必要的,因为 W 阶段在循环的早期结束,而 D 阶段能够获得该结果。


在指令 2(写入者)和指令 3(读取者)之间的 t3 上还有一个简单的 ALU-ALU 依赖性,即(写入后读取)风险,该图未标出,所以这是很好的证据,表明该图在显示所有危险方面是不完整的。


有时教育工作者只展示了写后读危害的最明显例子。还有许多其他危害经常被忽视。

另一个涉及负载危险。通常,负载危险被视为既需要前进又需要失速;如果在 ALU 的下一条指令中使用了加载结果。但是,如果加载指令之后是存储指令(存储加载的数据),则从 M(加载)到存储的 M 的转发可以在没有停顿的情况下缓解这种危险(与 X 到 X 转发可以缓解的方式非常相似)和 ALU 依赖风险)。

所以我们可能会注意到一条存储指令有两个寄存器源,但实际上直到 M 阶段才需要用于存储值的寄存器,而在 X (ALU) 中需要用于基地址计算的寄存器阶段。 (这使得 store 与 add 有点不同,它也有两个寄存器源,因为 X 阶段需要两者。)