举个例子:x86_64 CPU 读取 128 位指令。
据我了解,这几乎是 x86 处理器中发生的事情。否则,例如,不可能将 64 位数字添加到 64 位寄存器(对于大于 64 的数字,操作码将占用几位 + 64 位)。
我想知道的是指令中的位限制是什么,以及如果指令大于位(数据总线),如何读取指令。此外,我还知道大多数 RISC CPU 使用固定大小的指令,所以如果你直接传递一个数字操作数,指令的大小是否会增加一倍?
读取 128 位指令的 x86_64 CPU
这不会发生,最大指令大小定义为 15 个字节。您可以构建更长的指令,但它们将是无效的。
您不需要 16 个字节来获得采用 64 位立即操作数的指令。只有几个 x64 指令甚至可以首先做到这一点,例如mov r64, imm64
,它被编码为REX.W B8+r io
10 个字节。几乎所有采用立即数的 64 位 x64 指令都采用符号扩展的较短立即数,即 8 位或 32 位。
在 RISC ISA 中,通常不可能有一个与字长一样大的立即数,您必须分两步在寄存器中构造大值或从内存中加载它们。但是 x64 和它的 x86 根源一样,绝对不是 RISC。
我怀疑这个问题(部分)是由一个接一个地通过数据总线的指令的心理形象所激发的,这对 MIPS 等来说很好,但是对于没有对齐要求的可变长度指令,就像你在 x86 中那样,你可以不要那样做——无论你选择什么样的块,它可能(并且很可能是)直接通过一些指令。因此,从最简单的角度来看,解码是一个带有缓冲区的状态机,解码第一条指令并将其从缓冲区中删除,当有空间时填充更多字节(当然现在更复杂了)。
顺便说一句,嵌入到指令中的操作数数据称为“立即”数据。
这不是现代 CPU 的工作方式,但数据总线比最长指令窄实际上不是问题。
例如,8086 确实必须处理比其 16 位数据总线更宽的指令编码,并且没有任何 L1 缓存来隐藏这种影响。
据我了解,8086 只是不断将字(16 位)读入解码缓冲区,直到解码器一次看到整条指令。如果有剩余字节,则将其移动到解码缓冲区的前面。下一个 insn 的指令获取实际上与刚刚解码的指令的执行并行发生,但代码获取仍然是 8086 的主要瓶颈。
因此 CPU 只需要一个与允许的最大指令(不包括前缀)一样大的缓冲区。那是8086 的 6 个字节,这正是8086 的预取缓冲区的大小。
“直到解码器看到一条完整的指令”是一种简化:8086 分别解码前缀,并将它们“记住”为修饰符。8086 缺少后来 CPU 的 15 字节最大总 insn 长度限制,因此您可以在一条指令上使用重复前缀填充 64k CS 段)。
现代 CPU(如 Intel P6 和 SnB 系列)以至少 16B 的块从 L1 I-cache 获取代码,并实际并行解码多个指令。@Harold 很好地涵盖了您的其余问题。
另请参阅Agner Fog 的微架构指南以及x86标签 wiki 中的其他链接,以详细了解现代 x86 CPU 的工作原理。