ARM、Thumb 和 Thumb 2 指令编码之间有什么区别?

What is the difference between the ARM, Thumb and Thumb 2 instruction encodings?

我对指令集有点困惑。有 Thumb、ARM 和 Thumb 2。根据我的阅读,Thumb 指令都是 16 位的,但在 A​​RMv7M 用户手册(第 vi 页)中有 Thumb 16 位和 Thumb 32提到的位指令。

现在我要克服这个困惑了。据说Thumb 2支持16位和32位指令。那么 ARMv7M 实际上是否支持 Thumb 2 指令而不仅仅是 Thumb?

还有一件事。我可以说 Thumb(32 位)与同样是 32 位的 ARM 指令相同吗?

哦,ARM 和他们愚蠢的命名...

这是一个常见的误解,但官方并不存在 "Thumb-2 instruction set"。

忽略 ARMv8(其中一切都被重命名并且 AArch64 使事情复杂化),从 ARMv4T 到 ARMv7-A 有两个 指令集:ARM 和 Thumb。它们都是“32 位”的,因为它们在具有 32 位地址的 32 位宽寄存器中操作最多 32 位宽的数据。事实上,在它们重叠的地方,它们代表完全相同的指令 - 只有指令 encoding 不同,而 CPU 实际上只是有两个不同的解码前端它可以在其中切换的管道。为清楚起见,我现在将故意避免使用术语“32 位”和“16 位”...

ARM 指令具有固定宽度的 4 字节编码,需要 4 字节对齐。 Thumb 指令具有可变长度(2 或 4 字节,现在称为 "narrow" 和 "wide")编码,需要 2 字节对齐 - 大多数指令具有 2 字节编码,但 blblx 总是有 4 字节编码*。真正令人困惑的一点出现在 ARMv6T2 中,它引入了 "Thumb-2 Technology"。 Thumb-2 不仅包括向 Thumb 添加更多指令(主要使用 4 字节编码)以使其几乎与 ARM 保持一致,还包括扩展执行状态以允许有条件地执行大多数 Thumb 指令,最后引入一个全新的汇编语法(UAL,"Unified Assembly Language")取代了以前单独的 ARM 和 Thumb 语法,并允许编写一次代码并将其汇编到任一指令集而无需修改。

Cortex-M 架构仅实现 Thumb 指令集 - ARMv7-M (Cortex-M3/M4/M7) 支持大部分 "Thumb-2 Technology",包括 VFP 指令的条件执行和编码,而 ARMv6-M ( Cortex-M0/M0+) 仅以少量 4 字节系统指令的形式使用 Thumb-2。

因此,新的 4 字节编码(以及后来在 ARMv7 修订版中添加的编码)仍然是 Thumb 指令 - 它们的 "Thumb-2" 方面是它们 可以有 4 字节编码,并且它们可以(大部分)通过 it 有条件地执行(而且,我想,它们的 menmonics 只在 UAL 中定义)。

* 在ARMv6T2之前,bl(或blx)是作为4字节指令还是作为一对指令执行,其实是一个复杂的实现细节2 字节指令。架构定义是后者,但由于它们只能按顺序成对执行,因此出于性能原因将它们融合为一条指令不会有什么损失(除了能够在中途中断)。 ARMv6T2 只是根据融合的单指令执行重新定义了事物

除了 之外,正如它所暗示的那样,ARMv8 引入了一些新术语以试图减少混淆(当然会添加更多新术语):

有 32 位执行状态 (AArch32) 和 64 位执行状态 (AArch64)。

32 位执行状态支持两种不同的指令集:T32(“Thumb”)和 A32(“ARM”)。 64位执行状态只支持一种指令集——A64。

与所有 A32 一样,所有 A64 指令的大小都是 32 位(4 字节),需要 4 字节对齐。

Many/most A64 指令可以在 32 位和 64 位寄存器上运行(或者可以说是同一底层 64 位寄存器的 32 位或 64 位视图)。

所有实现 AArch32 的 ARMv8 处理器(与所有 ARMv7 处理器一样)都支持 T32 指令集中的 Thumb-2 指令。

并非所有 ARMv8-A 处理器都实现 AAarch32,有些处理器不实现 AArch64。有些处理器两者都支持,但只支持较低异常级别的 AArch32。

请参考https://developer.arm.com/documentation/ddi0344/c/programmer-s-model/thumb-2-instruction-set 它详细解释了 Thumb2 架构的增强。同样隐含地涵盖了ARM、Thumb和Thumb2指令集描述。

令我感到困惑的是,Cortex M3 具有 4 字节指令,但不执行 ARM 指令。或者 CPUs 能够具有 2 字节和 4 字节的操作码,但也能够执行 ARM 指令。所以我看了一本关于 Arm 的书,现在我对它的理解稍微好一点了。尽管如此,命名和重叠仍然让我感到困惑。我在想先比较几个 CPU 然后再讨论 ISA 会很有趣。

比较几个 CPU 以及它们可以做什么以及它们如何重叠:

  • 皮质M0/M0+/M1/M23被认为是Thumb(Thumb-1)并且可以执行 2 字节 操作码,这些操作码与其他操作码相比是有限的。但是,mrsmsrbldmbdsbisb等一些指令来自Thumb-2,是4 字节。 Cortex M0/M0+/M1 是 ARMv6,而 Cortex M23 是 ARMv8。 Thumb-1 指令在 ARMv7 中得到扩展,因此可以说 ARMv8 Cortext M23 支持更完整的 Thumb-1(it 指令除外),而 ARMv6 Cortex M0/M0+ 仅支持 ISA 的一个子集(它们特别缺少 itcbzcbnz 说明)。我可能是错的(如果这不对,请纠正我),但注意到一些有趣的事情,我看到只有 CPUs 完全支持 Thumb-1 是 CPUs 已经支持 Thumb-2 作为好吧,我不知道只有 Thumb-1 CPU 支持 100% 的 Thumb-1。我认为这是因为 it 可以被视为 Thumb-2 操作码,它是 2 字节并且本质上被添加到 Thumb-1。在 Thumb-1 CPUs 上,4 字节操作码可以看作是两个 2 字节来表示 4 字节操作码。

  • Cortex M3/M4/M7/M33/M35P/M55可以执行2字节和4字节的操作码,都是Thumb-1 和 Thumb-2 并支持全套 ISA。 2-byte和4-byte opcode混合的比较均匀,而上面的CortexM0/M0+/M1/M23大部分时间偏向于使用2-byte opcode。 Cortex M3/M4/M7 是 ARMv7,而 Cortex M33/M35P/M55 是 ARMv8.

  • Cortex A/R 可以接受 ARM 和 Thumb 操作码,因此有 2字节和4字节。要在模式之间切换,PC 需要偏移一个字节(强制不对齐),这可以通过分支指令 bx 来完成,该指令设置 CPSRT 位和根据地址的最低位切换模式。这很有效,例如,当调用子程序时,PC(及其模式)被保存,然后在子程序中它可以切换到 Thumb 模式,但是当从 Thumb 模式返回时,它将恢复 PC(及其 T 位)和毫无问题地切换回调用者的状态(ARM 或 Thumb 模式)。

  • ARM7 只支持 ARMv3 4-byte ISA

  • ARM7T 同时支持 Thumb-1 和 ARM ISA(2 字节和 4 字节)

  • ARM11(ARMv6、ARMv6T2、ARMv6Z、ARMv6K)支持Thumb-1、Thumb-2和ARM ISA

我引用的书指出,在 ARMv7 和更新版本 中,架构从冯诺依曼(数据和指令共享总线)切换到哈佛(专用总线)以获得更好的性能.然而,绝对术语“和更新”是不正确的,因为 ARMv8 是更新的,而 ARMv8 Cortex M23 是 Von Neumann。

ISA 是:

  • ARM有16个寄存器(R0-R12,SP,LR,PC),只有4字节的操作码,ISA有修改,但是它们只是 4 字节的操作码。

  • Thumb(又名 Thumb-1)将 16 个寄存器拆分为低位 (R0-R7) 和高位 (R8-R12、SP、LR、PC ), 大多数指令只能访问低位集,而只有一些指令可以访问高位集。只有 2 字节的操作码。在具有 16 位总线(并且必须分两步进行 32 位字访问)的低端设备上,当它们执行 2 字节操作码时性能更好,因为它与它们的总线匹配。命名让我感到困惑,Thumb 可以用作 Thumb-1 和 Thumb-2 的家族术语,或者有时 Thumb 只能用于 Thumb-1。我认为 Thumb-1 不是正式的 Arm 术语,只是我看到有人用它来区分两个 ISA 的 Thumb 系列和第一个 Thumb ISA 之间的区别。 ARM 中的指令可以有可选的 s 后缀来更新 CPSR 寄存器(例如 andsorrsmovsaddssubs 指令),而在 Thumb-1 中,s 始终打开并且它始终保存 CPSR 寄存器。在一些较旧的工具链中,不需要隐式 s,但是在统一汇编语言 (UAL) 的努力下,现在需要显式指定 s,即使没有不使用 s.

  • Thumb-2 是对 Thumb 的扩展,可以像 ARM 一样访问所有寄存器,具有 4 字节操作码,与 ARM 相比有一些差异。在汇编中,可以使用 .n.w 后缀强制 Thumb-1 2 字节窄操作码和 Thumb-2 4 字节宽操作码(示例 orr.w)。 ARM 和 Thumb-2 操作码 formats/encodings 不同,它们的功能也不同。可以使用指令的条件执行,但前提是 it (if-then) instruction/block 是前置的。这可以明确或暗示地完成(并由用户背后的工具链完成)。混淆实际上可能是好的,因为 Arm(公司)希望它们相似,统一汇编语言 (UAL) 付出了很多努力,因此为 ARM 制作的汇编文件可以在 Thumb-2 上编译而无需更改。如果我理解正确,那不能 100% 保证,并且可能会出现一些边缘情况,其中 ARM 程序集无法编译为 Thumb-2,这是另一个不完全正确的绝对陈述。例如,ARM7 bl 指令可以寻址 +-32MB,而在 Cortex M3 上它只能寻址 +-16MB。与 Thumb-1 相比,这种情况要好得多,其中 ARM 程序集更有可能被重写为目标 Thumb-1,而 ARM 到 Thumb-2 重写的可能性较小。另一个区别是数据处理指令。 ARM 和 Thumb-2 都支持 8 位立即数,而 ARM 只能向右旋转位且只能旋转偶数位,而 Thumb 可以向左旋转 even/odd 位数量,最重要的是允许重复字节模式,例如 0xXYXYXYXY0x00XY00XY0xXY00XY00。因为移位是旋转的,左右移位可以通过'overflowing'实现,向一个方向移位太多以至于实际上是向相反方向移位1 << (32 - n) == 1 >> n

总之,一些 Arm CPU 可以做到:

  • 仅 4 字节操作码指令,纯 ARM ISA
  • 2-byte/4-byte Thumb-1/Thumb-2 ISA 的重点是大部分时间使用 2 字节,只有少数 4 字节操作码,这些通常被标记为 Thumb(Thumb-1 ) 2-byte opcode CPUs (和少数4-byte opcodes 有时没有提到)
  • 2-byte/4-byte Thumb-1/Thumb-2 ISA 并且更均匀地混合在 2 字节和 4 字节操作码之间,通常标记为 Thumb-2
  • 2-byte/4-byte 操作码通过在 ARM/Thumb 模式之间切换

此信息参考:ARM Assembly Language Programming & Architecture Muhammad Ali Mazidi et al 2016。这本书是在公司名称从 ARM 更改为 Arm 之前编写的,因此有时在引用公司 Arm 和当ARM ISA.

Thumb: 16 位指令集

ARM: 32 位宽指令集因此更灵活的指令和更少的代码密度

Thumb2(混合 16/32 位):某种程度上是 A​​RMthumb(16)(将它们混合),以获得 ARM 的 performance/flexibility 和 Thumb 的指令密度。因此 Thumb2 指令可以是具有 32 位宽指令的 ARM(仅是其子集)或具有 16 位宽的 Thumb 指令。