CPU如何将指令与数据区分开?
CPU在执行代码时如何确定指令长度(从1字节到最大15字节不等)?如果假设cpu不能确定指令的长度,则可以将数据作为指令的一部分。在这种情况下,可能会出现不希望的结果,或者CPU不执行该指令(如果不在操作码表中)。 cpu如何确定是数据还是指令?
不必预测。 在逻辑上,它一次解码一个字节,直到看到完整的指令。(或disp32或imm32的dword块,或指令的其他多字节部分由较早的字节暗示。)指令的长度为由前缀和操作码+ modrm + SIB字节表示。在查看了这些内容之后,CPU会确定要提取多少个指令字节。
但是真正的CPU只需要给出这样做的错觉,并且只要它们最终不属于应该执行的指令的一部分,只要它最终做对了事情,就可以查看后面的字节。
实际上,在实际的实现中,只要您最终做正确的事,就可以推测性地加载后面的字节没有问题。
例如L1指令缓存使用64字节的行,因此逻辑执行到达一个字节意味着整个64字节的内存块都将位于I缓存中,即使它在L1 D缓存中也是[[also相同行中其他字节上的数据加载指令。
当然,从L1I缓存中提取数据也不是一次是单个字节。在现代x86上,解码查看32或16字节的块以查找指令边界。例如让我们看一下P6系列,它没有uop缓存,因此它总是从L1I提取/解码。从Agner Fog's microarch PDF,在PPro / PII / PIII部分中:
预解码器流水线级然后找到指令边界(假设它们都是有效指令),然后(按照分支预测单元的预测),将3条指令的机器代码并行发送到3个解码器。 (Core2扩展为4个解码器,Skylake扩展为5个解码器,即使管道宽度保持在4 uop宽)。6.2指令提取
从代码缓存中按对齐的16字节块中提取指令代码
成双精度可以容纳两个16字节块的缓冲区。双缓冲区的目的是为了使其可以解码跨越16字节边界的指令(即可整除的地址16)。代码将从双缓冲区传递到块中的解码器,我将调用IFETCH块(指令提取块)。 IFETCH块最长为16个字节。在在大多数情况下,指令提取单元使每个IFETCH块从一条指令开始边界,而不是16字节边界。但是,指令提取单元需要来自指令长度解码器的信息,以便知道指令在哪里边界是。如果无法及时获得此信息,则它可能会启动一个IFETCH块在16字节边界处。这种复杂性将在下面更详细地讨论。
如果某处有非法指令(或无条件的jmp
或恰好被取走的jcc
,则后来的“指令”是没有意义的,一旦发现这一事实便被丢弃。
CPU可以看一堆字节,然后仅使用逻辑上应作为指令执行的字节
。更为有用。