可以制造支持多个 ISA 的处理器吗? (例如:ARM + x86)
Could a processor be made that supports multiple ISAs? (ex: ARM + x86)
英特尔自其 Skylake(?) 架构以来一直在内部将 CISC 指令解码为 RISC 指令,而 AMD 自其 K5 处理器以来一直在这样做。那么这是否意味着 x86 指令在执行期间被翻译成一些奇怪的内部 RISC ISA?如果这是正在发生的事情,那么我想知道是否有可能创建一个处理器来理解(即在内部转换为它自己的专有指令)x86 和 ARM 指令。如果可能的话,性能会怎样?为什么还没有完成?
ISA 越不同,就越难。 而且它会花费更多的开销,尤其是 back-end。 这不像将不同的 front-end 拍打到常见的 back-end 微体系结构设计那么容易。
如果 只是 不同解码器的裸片面积成本,而不是其他功率或性能差异,那么在如今晶体管预算很大的情况下,这将是微不足道的,而且完全可行。 (在芯片的关键部分占据 space 将重要的东西彼此远离仍然是一种成本,但这不太可能成为 front-end 中的问题)。时钟甚至电源门控都可以完全关闭未使用的解码器。但正如我所说,没那么简单,因为 back-end 必须设计为支持 ISA 的指令和其他规则/功能; CPUs 不解码为完全通用/中性 RISC back-end。相关:Why does Intel hide internal RISC core in their processors? 对现代英特尔设计中的内部 RISC-like 微指令有一些想法和信息。
例如,将 ARM 支持功能添加到 Skylake 会使 power-efficient 在 运行 纯 x86 代码时变得更慢,并且会占用更多芯片面积。这在商业上不值得,因为它的市场有限,而且需要特殊的 OS 或管理程序软件才能利用它。 (虽然随着 AArch64 变得更加相关,这可能会开始改变,这要归功于 Apple。)
可以 运行 ARM 和 x86 代码的 CPU 在任何一个上都比只处理一个的纯设计差得多。
高效 运行ning 32 位 ARM 需要支持完全预测的执行,包括加载/存储的故障抑制。 (与 AArch64 或 x86 不同,它们只有 ALU-select 类型的指令,例如 csinc
vs. cmov
/ setcc
,它们对 FLAGS 及其其他输入具有正常的数据依赖性.)
ARM 和 AArch64(尤其是 SIMD shuffle)有几条产生 2 个输出的指令,而几乎所有 x86 指令只写一个输出寄存器。因此,x86 微体系结构旨在跟踪最多读取 3 个输入(Haswell/Broadwell 之前为 2 个)的 uops,并且仅写入 1 个输出(或 1 个 reg + EFLAGS)。
x86 需要跟踪 CISC 指令的单独组件,例如内存源操作数的加载和 ALU 微指令,或内存目标的加载、ALU 和存储。
x86 需要连贯的指令缓存,并窥探修改已经获取的指令并在流水线中运行的存储,或者至少处理 x86 的某种方式强 self-modifying-code ISA 保证 (Observing stale instruction fetching on x86 with self-modifying code).
x86 需要 strongly-ordered memory model。 (程序顺序 + store-forwarding 的存储缓冲区)。您必须将它放入您的加载和存储缓冲区中,所以我预计即使 运行 宁 ARM 代码,这样的 CPU 基本上仍然会使用 x86 的更强大的内存模型。 (现代英特尔 CPUs 推测性地提前加载并在 mis-speculation 上执行内存命令机器清除. 除非是由于 mis-predicting 负载是否正在通过该线程重新加载最近的商店;当然,这仍然必须正确处理。)
纯 ARM 可以有更简单的加载/存储缓冲区,它们之间的交互不那么多。 (除了为了让 stlr
/ ldapr
/ ldar
发布/获取 / acquire-seq-cst 更便宜,而不仅仅是完全拖延。)
不同的 page-table 格式。 (您可能会选择其中之一供 OS 使用,并且仅在本机内核下为 user-space 支持另一个 ISA。)
如果您确实尝试完全处理来自两个 ISA 的特权/内核内容,例如因此您可以使用任一 ISA 的 VM 进行硬件虚拟化,您还可以使用 control-register 和调试工具之类的东西。
更新:Apple M1 确实 支持强大的 x86 风格 TSO 内存模型,allowing efficient+correct binary translation of x86-64 machine code into AArch64 machine code, without needing to use ldapr
/ stlr
for every load and store. It also has a weak mode for running native AArch64 code, toggleable by the kernel.
在 Apple 的 Rosetta 二进制翻译中,软件会处理我提到的所有其他问题; CPU 只是在执行原生 AArch64 机器代码。 (而且 Rosetta 只处理 user-space 程序,因此甚至不需要像那样模拟 x86 page-table 格式和语义。)
其他 ISA 组合已经存在,特别是 AArch64 + ARM,但 x86-64 和 32 位 x86 的机器代码格式略有不同,并且寄存器更大放。这些 ISA 对当然被设计为兼容,并且新 ISA 的内核支持 运行 将旧 ISA 作为 user-space 进程。
在最简单的一端,我们有 x86-64 CPUs 支持 运行ning 32 位 x86 机器代码(在“兼容模式”下)在 64 位核心。他们完全使用相同的管道 fetch/decode/issue/out-of-order-exec pipeline for al 模式。 64 位 x86 机器代码有意与 16 位和 32 位模式非常相似,因此可以使用相同的解码器,只有少数 mode-dependent 解码差异。 (比如 inc/dec vs. REX 前缀。)AMD 故意非常保守,不幸的是,对于 64 位模式,许多小的 x86 缺陷保持不变,以保持解码器尽可能相似。 (也许在 AMD64 甚至没有流行的情况下,他们不想被困在人们不会使用的额外晶体管上。)
AArch64 和 ARM 32 位是独立的 machine-code 格式,在编码方面存在显着差异。例如立即操作数的编码不同,我假设大多数操作码都是不同的。大概管道有 2 个独立的解码器块,并且 front-end 根据模式通过一个或另一个路由指令流。两者都相对容易解码,不像 x86,所以这大概没问题;两个块都不必很大就可以将指令转换为一致的内部格式。不过,支持 32 位 ARM 确实意味着以某种方式在整个管道中实现对预测的有效支持。
早期的 Itanium (IA-64) 也有对 x86 的硬件支持,定义了 x86 寄存器状态映射到 IA-64 寄存器状态的方式。这些 ISA 完全 不同。我的理解是 x86 支持或多或少是“固定的”,芯片的一个单独区域专用于 运行ning x86 机器代码。性能很差,比好的软件仿真还差,所以一旦准备就绪,硬件设计就会放弃它。 (https://en.wikipedia.org/wiki/IA-64#Architectural_changes)
So does this mean that the x86 instructions get translated to some weird internal RISC ISA during execution?
是的,但是“RISC ISA”与 ARM 不相似。例如它具有 x86 的所有怪癖,比如如果移位计数为 0,则移位保持 FLAGS 不变。(现代英特尔通过将 shl eax, cl
解码为 3 微码来处理这个问题;Nehalem 和更早的停滞了 front-end 如果后面的指令想从轮班中读取 FLAGS。)
可能需要支持的 back-end 怪癖的一个更好的例子是 x86 部分寄存器,比如写入 AL 和 AH,然后读取 EAX。 back-end 中的 RAT(寄存器分配 table)必须跟踪所有这些,并发出合并 uops 或者它如何处理它。 (参见 )。
简短的回答。是的,可以做到。 See/Google“大型机微代码”。是的,已经用大型机和小型机完成了。因为现在 cpus 已经针对它们自己的体系结构进行了高度优化,如果使用替代微代码,则不太可能获得良好的性能。经验表明,cpu x 在微码中被 cpu y 模拟是一个 non-trivial 问题。你最终需要比最初的设计师更了解这两个 cpu。天堂会帮助您进行面具变化。最好编写更高级别的仿真器。经验之谈。
英特尔自其 Skylake(?) 架构以来一直在内部将 CISC 指令解码为 RISC 指令,而 AMD 自其 K5 处理器以来一直在这样做。那么这是否意味着 x86 指令在执行期间被翻译成一些奇怪的内部 RISC ISA?如果这是正在发生的事情,那么我想知道是否有可能创建一个处理器来理解(即在内部转换为它自己的专有指令)x86 和 ARM 指令。如果可能的话,性能会怎样?为什么还没有完成?
ISA 越不同,就越难。 而且它会花费更多的开销,尤其是 back-end。 这不像将不同的 front-end 拍打到常见的 back-end 微体系结构设计那么容易。
如果 只是 不同解码器的裸片面积成本,而不是其他功率或性能差异,那么在如今晶体管预算很大的情况下,这将是微不足道的,而且完全可行。 (在芯片的关键部分占据 space 将重要的东西彼此远离仍然是一种成本,但这不太可能成为 front-end 中的问题)。时钟甚至电源门控都可以完全关闭未使用的解码器。但正如我所说,没那么简单,因为 back-end 必须设计为支持 ISA 的指令和其他规则/功能; CPUs 不解码为完全通用/中性 RISC back-end。相关:Why does Intel hide internal RISC core in their processors? 对现代英特尔设计中的内部 RISC-like 微指令有一些想法和信息。
例如,将 ARM 支持功能添加到 Skylake 会使 power-efficient 在 运行 纯 x86 代码时变得更慢,并且会占用更多芯片面积。这在商业上不值得,因为它的市场有限,而且需要特殊的 OS 或管理程序软件才能利用它。 (虽然随着 AArch64 变得更加相关,这可能会开始改变,这要归功于 Apple。)
可以 运行 ARM 和 x86 代码的 CPU 在任何一个上都比只处理一个的纯设计差得多。
高效 运行ning 32 位 ARM 需要支持完全预测的执行,包括加载/存储的故障抑制。 (与 AArch64 或 x86 不同,它们只有 ALU-select 类型的指令,例如
csinc
vs.cmov
/setcc
,它们对 FLAGS 及其其他输入具有正常的数据依赖性.)ARM 和 AArch64(尤其是 SIMD shuffle)有几条产生 2 个输出的指令,而几乎所有 x86 指令只写一个输出寄存器。因此,x86 微体系结构旨在跟踪最多读取 3 个输入(Haswell/Broadwell 之前为 2 个)的 uops,并且仅写入 1 个输出(或 1 个 reg + EFLAGS)。
x86 需要跟踪 CISC 指令的单独组件,例如内存源操作数的加载和 ALU 微指令,或内存目标的加载、ALU 和存储。
x86 需要连贯的指令缓存,并窥探修改已经获取的指令并在流水线中运行的存储,或者至少处理 x86 的某种方式强 self-modifying-code ISA 保证 (Observing stale instruction fetching on x86 with self-modifying code).
x86 需要 strongly-ordered memory model。 (程序顺序 + store-forwarding 的存储缓冲区)。您必须将它放入您的加载和存储缓冲区中,所以我预计即使 运行 宁 ARM 代码,这样的 CPU 基本上仍然会使用 x86 的更强大的内存模型。 (现代英特尔 CPUs 推测性地提前加载并在 mis-speculation 上执行内存命令机器清除. 除非是由于 mis-predicting 负载是否正在通过该线程重新加载最近的商店;当然,这仍然必须正确处理。)
纯 ARM 可以有更简单的加载/存储缓冲区,它们之间的交互不那么多。 (除了为了让
stlr
/ldapr
/ldar
发布/获取 / acquire-seq-cst 更便宜,而不仅仅是完全拖延。)不同的 page-table 格式。 (您可能会选择其中之一供 OS 使用,并且仅在本机内核下为 user-space 支持另一个 ISA。)
如果您确实尝试完全处理来自两个 ISA 的特权/内核内容,例如因此您可以使用任一 ISA 的 VM 进行硬件虚拟化,您还可以使用 control-register 和调试工具之类的东西。
更新:Apple M1 确实 支持强大的 x86 风格 TSO 内存模型,allowing efficient+correct binary translation of x86-64 machine code into AArch64 machine code, without needing to use ldapr
/ stlr
for every load and store. It also has a weak mode for running native AArch64 code, toggleable by the kernel.
在 Apple 的 Rosetta 二进制翻译中,软件会处理我提到的所有其他问题; CPU 只是在执行原生 AArch64 机器代码。 (而且 Rosetta 只处理 user-space 程序,因此甚至不需要像那样模拟 x86 page-table 格式和语义。)
其他 ISA 组合已经存在,特别是 AArch64 + ARM,但 x86-64 和 32 位 x86 的机器代码格式略有不同,并且寄存器更大放。这些 ISA 对当然被设计为兼容,并且新 ISA 的内核支持 运行 将旧 ISA 作为 user-space 进程。
在最简单的一端,我们有 x86-64 CPUs 支持 运行ning 32 位 x86 机器代码(在“兼容模式”下)在 64 位核心。他们完全使用相同的管道 fetch/decode/issue/out-of-order-exec pipeline for al 模式。 64 位 x86 机器代码有意与 16 位和 32 位模式非常相似,因此可以使用相同的解码器,只有少数 mode-dependent 解码差异。 (比如 inc/dec vs. REX 前缀。)AMD 故意非常保守,不幸的是,对于 64 位模式,许多小的 x86 缺陷保持不变,以保持解码器尽可能相似。 (也许在 AMD64 甚至没有流行的情况下,他们不想被困在人们不会使用的额外晶体管上。)
AArch64 和 ARM 32 位是独立的 machine-code 格式,在编码方面存在显着差异。例如立即操作数的编码不同,我假设大多数操作码都是不同的。大概管道有 2 个独立的解码器块,并且 front-end 根据模式通过一个或另一个路由指令流。两者都相对容易解码,不像 x86,所以这大概没问题;两个块都不必很大就可以将指令转换为一致的内部格式。不过,支持 32 位 ARM 确实意味着以某种方式在整个管道中实现对预测的有效支持。
早期的 Itanium (IA-64) 也有对 x86 的硬件支持,定义了 x86 寄存器状态映射到 IA-64 寄存器状态的方式。这些 ISA 完全 不同。我的理解是 x86 支持或多或少是“固定的”,芯片的一个单独区域专用于 运行ning x86 机器代码。性能很差,比好的软件仿真还差,所以一旦准备就绪,硬件设计就会放弃它。 (https://en.wikipedia.org/wiki/IA-64#Architectural_changes)
So does this mean that the x86 instructions get translated to some weird internal RISC ISA during execution?
是的,但是“RISC ISA”与 ARM 不相似。例如它具有 x86 的所有怪癖,比如如果移位计数为 0,则移位保持 FLAGS 不变。(现代英特尔通过将 shl eax, cl
解码为 3 微码来处理这个问题;Nehalem 和更早的停滞了 front-end 如果后面的指令想从轮班中读取 FLAGS。)
可能需要支持的 back-end 怪癖的一个更好的例子是 x86 部分寄存器,比如写入 AL 和 AH,然后读取 EAX。 back-end 中的 RAT(寄存器分配 table)必须跟踪所有这些,并发出合并 uops 或者它如何处理它。 (参见
简短的回答。是的,可以做到。 See/Google“大型机微代码”。是的,已经用大型机和小型机完成了。因为现在 cpus 已经针对它们自己的体系结构进行了高度优化,如果使用替代微代码,则不太可能获得良好的性能。经验表明,cpu x 在微码中被 cpu y 模拟是一个 non-trivial 问题。你最终需要比最初的设计师更了解这两个 cpu。天堂会帮助您进行面具变化。最好编写更高级别的仿真器。经验之谈。