据我所知,两条指令的操作码和功能码均为 0,那么计算机如何知道它在做什么?
正如 Jester 所说,如果 MIPS CPU 不想做任何特殊的性能优化,Doesn't 必须区分。
sll $0, $0, 0
已经没有架构效果,因为写入 $0
被丢弃,并且它没有副作用(MIPS 没有标志/条件代码寄存器)。如此简单的硬件就可以让它通过管道运行。
有一个商定的
nop
操作码的要点是,如果硬件想要寻找一个特殊情况甚至不执行它,那么只有一个位模式必须匹配,而不是考虑每一个指令选择写入$0
(可能仍然会出错的负载除外。)
因此编译器/汇编程序的开发人员不必猜测对于某些硬件来说什么
nop
可能是最便宜的。硬件可能做的事情包括:
nop
和sll $t0, $t1, 12
,即使它通常不能在同一周期内运行两个班次。$0
上的每次读写进行特殊处理,则可以跳过nop
。 (仅适用于没有旁路转发的玩具 CPU,见下文。)甚至
sll $t0, $t0, 0
也没有架构效果,因为它用它已经拥有的相同值写入寄存器。但这是一个更糟糕的选择,因为危险检测通常会查看寄存器读写,因此它可能会导致停顿,或者 $t0
在像 R10000 这样的无序执行 MIPS 上的依赖链更长。但是,如果 MIPS 没有零寄存器,那么同意作为 NOP 将是一个合理的选择,除了在 MIPS 1 上将它放在写 $t0
的 loat 的加载延迟槽中是不安全的
.
对于根本没有尝试特殊情况
lw $0, (mem)
或零寄存器的硬件,是否存在带有nop
/nop
的任何可能的极端情况,零寄存器丢弃写入和读取作为零处理仅在注册文件?
在那种情况下,它会看到一条指令在下一条指令中读取加载结果。在 MIPS I 上,这会为读取的值提供不可预测的结果,因为它不会因旁路转发无法处理的危险而停止。 (在后来的 MIPS 上,它停止了;加载延迟槽不是体系结构的,只是性能的。)当然,结果最终只是写入零寄存器,所以没有明显的差异。
但是如果简单的硬件没有特殊情况下绕过转发的零寄存器,像
addiu $0, $0, 123
/addi $1, $0, 0
这样的东西可以复制一个非零值。因此,正确的 MIPS 设计不可能那么简单,并且在为旁路转发进行危险检测时确实必须已经有特殊情况$zero
,以确保它不会旁路转发到 $0
的读取,这是需要始终读零。
停止而不是旁路转发的 MIPS 设计不必在危险检测中特例
$0
,因为所有值都将通过寄存器文件。但这可能不是 MIPS 架构师的考虑因素,因为旁路转发对于大多数代码的良好性能至关重要。