Kon*_*ach 12
我觉得你的术语很混乱.
处理器将一个停顿注入到管道中以解决数据危险(处理指令所需的数据尚未可用的情况.A NOP只是没有副作用的指令.
回想一下5管道阶段的经典RISC管道:
考虑代码段:
add $t0, $t1, $t1
sub $t2, $t0, $t0
Run Code Online (Sandbox Code Playgroud)
从这里可以看出,第二条指令依赖于第一条指令的结果.这是一个数据危险:写后读(RAW); 一个真正的依赖.
该sub要求的价值add在其EX阶段,但add将只在其MEM阶段-价值将无法使用,直到WB阶段:
+------------------------------+----+----+----+-----+----+---+---+---+---+
| | CPU Cycles |
+------------------------------+----+----+----+-----+----+---+---+---+---+
| Instruction | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+------------------------------------------------------------------------+
| 0 | add $t0, $t1, $t1 | IF | ID | EX | MEM | WB | | | | |
| 1 | sub $t2, $t0, $t0 | | IF | ID | EX | | | | | |
+---------+--------------------+----+----+----+-----+----+---+---+---+---+
Run Code Online (Sandbox Code Playgroud)
该问题的一个解决方案是处理器插入停顿或使管道起泡直到数据可用.
+------------------------------+----+----+----+-----+----+----+-----+---+----+
| | CPU Cycles |
+------------------------------+----+----+----+-----+----+----+-----+----+---+
| Instruction | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+----------------------------------------------------------------------------+
| 0 | add $t0, $t1, $t1 | IF | ID | EX | MEM | WB | | | | |
| 1 | sub $t2, $t0, $t0 | | IF | ID | S | S | EX | MEM | WB | |
+----------+-------------------+----+----+----+-----+----+---+---+---+-------+
Run Code Online (Sandbox Code Playgroud)
A NOP是无效的指令(没有副作用).MIPS汇编程序通常支持nop指令,但在MIPS中这相当于 sll $zero $zero 0.
该指令将占用管道的所有5个阶段.它最常用于填充跳转或分支的分支延迟槽,当在该槽中没有其它任何有用的东西时.
j label
nop # nothing useful to put here
Run Code Online (Sandbox Code Playgroud)
如果您使用的是MIPS仿真器,则可能需要启用分支延迟时隙仿真才能看到此情况.(例如,spim使用-delayed_branches参数)