Risc-V 程序集 - 使代码可操作所需的气泡数量 - [假设]

Risc-V Assembly - amount of bubbles needed to make the code operational - [Hypothetical]

我想知道为什么在流水线 RiscV 上执行此汇编代码时 - 不会自动停止 - 转发(内部寄存器文件 WB->DEC 转发除外)我们需要在第三个命令,一个 NOP 就够了吗?

addi t0, x0, 0
addi t1, x0, 5
addi s1, x0, 0x200 //why are two NOPS required after this command?
beq t1, t0, finish

这是我的思路-在一个nop之后,第一个命令完成编译,我们可以将t1从第二个命令的WB转发到beq的EXE中。我哪里错了?

正如 Erik 所说,不需要 NOP 指令。 CPU 实现应该处理依赖关系并在需要时停止管道。如果由于某种原因,实现没有做到这一点(我将其称为 BUG),有解决方法可以在后期修复它,编译器在检测依赖项时注入 nop 等。

如果 CPU 支持转发,就像您在传统的 5 级流水线 CPU 上所说的那样,那么就不需要 NOP。当 BEQ 指令到达 CPU 解码阶段时, t0 已经写入寄存器文件,而 t1 可以转发。

因此,在为此工作了几个小时之后,这里是解决方案: 需要两个关键事实:

  • Beq 只能从 WB 转发到,因为它的分支条件是计算分支计算器并且转发只存在于 ALU。
  • 根据问题说明,我们不能从 WB->DEC 转发,所以基本上我们不能转发到 Beq。 让我们编写阶段和“运行 程序”:
IF DEC EXE MEM WB 
1
2   1
3   2   1
4   3   2   1 
    4   3   2  1
  • 注意我们无法执行 4 (beq t1, t0, finish),因为它依赖于指令 2 中 t1 的值。我们必须等待 t1 的值。 MEM->DEC 转发不存在。我们只能在 DEC 阶段获取新的 t1,因为所有到 EXE 的转发都链接到 ALU,并且我们在无法影响的比较器处计算分支条件,因此我们必须等待并放置一个 NOP。让我们继续。
IF DEC EXE MEM WB
    4  NOP  3  2 
  • 注意我们仍然不能做任何事情 - 我们正在等待 t1 但我们没有 WB->DEC 转发(如问题中所述),所以我们必须等待 2 完成它的 WB在 DEC 阶段,以便我们可以获取 t1 的更新值,因此我们必须放置另一个 NOP。我们继续。
IF DEC EXE MEM WB
    4  NOP NOP 3 - notice 2 has finished, we can now continue with the correct t1.
        4  NOP NOP
            4  NOP
                4
DONE.

是的