我对指令集有点困惑。有 Thumb、ARM 和 Thumb 2。根据我的阅读,Thumb 指令都是 16 位的,但在ARMv7M 用户手册(第 vi 页)中提到了 Thumb 16 位和 Thumb 32 位指令。
现在我必须克服这种困惑。据说 Thumb 2 支持 16 位和 32 位指令。那么 ARMv7M 实际上是否支持 Thumb 2 指令而不仅仅是 Thumb?
还有一件事。我可以说 Thumb(32 位)与同样是 32 位的 ARM 指令相同吗?
哦,ARM 和他们愚蠢的命名......
这是一个常见的误解,但官方并没有“Thumb-2 指令集”之类的东西。
忽略 ARMv8(所有内容都被重命名并且 AArch64 使事情复杂化),从 ARMv4T 到 ARMv7-A 有两个指令集:ARM 和 Thumb。从某种意义上说,它们都是“32 位”,它们在具有 32 位地址的 32 位宽寄存器中操作高达 32 位宽的数据。事实上,它们重叠的地方代表完全相同的指令——只是指令编码不同,CPU实际上只有两个不同的解码前端到它的流水线,它可以在它们之间切换。为了清楚起见,我现在将故意避免使用“32 位”和“16 位”这两个术语……
ARM 指令具有固定宽度的 4 字节编码,需要 4 字节对齐。Thumb 指令具有可变长度(2 或 4 字节,现在称为“窄”和“宽”)编码,需要 2 字节对齐 - 大多数指令具有 2 字节编码,但bl
始终blx
具有 4 字节编码*. 真正令人困惑的是 ARMv6T2,它引入了“Thumb-2 技术”。Thumb-2 不仅包括向 Thumb 添加更多指令(主要使用 4 字节编码)以使其几乎与 ARM 相提并论,还包括扩展执行状态以允许有条件地执行大多数 Thumb 指令,最后引入了一个全新的汇编语法(UAL,“统一汇编语言”)取代了以前单独的 ARM 和 Thumb 语法,允许编写一次代码并将其汇编到任一指令集而无需修改。
Cortex-M 架构仅实现 Thumb 指令集 - ARMv7-M (Cortex-M3/M4/M7) 支持大部分“Thumb-2 技术”,包括 VFP 指令的条件执行和编码,而 ARMv6-M (Cortex- M0/M0+) 仅以少数 4 字节系统指令的形式使用 Thumb-2。
因此,新的 4 字节编码(以及后来在 ARMv7 修订版中添加的那些)仍然是Thumb 指令- 它们的“Thumb-2”方面是它们可以具有4 字节编码,并且它们可以(大部分)有条件地通过执行it
(并且,我想,他们的 menmonics 只在 UAL 中定义)。
bl
* 在 ARMv6T2 之前, (或blx
)是作为 4 字节指令执行还是作为一对 2 字节指令执行,实际上是一个复杂的实现细节。架构定义是后者,但由于它们只能作为一对按顺序执行,因此出于性能原因将它们融合到一条指令中几乎没有损失(除了中途中断的能力)。ARMv6T2 只是在融合的单指令执行方面重新定义了事物
除了Notlikethat's answer之外,正如它所暗示的那样,ARMv8 引入了一些新术语来尝试减少混淆(当然添加更多新术语):
有 32 位执行状态(AArch32)和 64 位执行状态(AArch64)。
32 位执行状态支持两种不同的指令集:T32(“Thumb”)和 A32(“ARM”)。64 位执行状态只支持一种指令集——A64。
与所有 A32 一样,所有 A64 指令的大小都是 32 位(4 字节),需要 4 字节对齐。
许多/大多数 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 指令集描述。
让我感到困惑的是具有 4 字节指令但不执行 ARM 指令的 Cortex M3。或者 CPU 能够具有 2 字节和 4 字节操作码,但也能够执行 ARM 指令。所以我读了一本关于 Arm 的书,现在我对它的理解稍微好一些。尽管如此,命名和重叠仍然让我感到困惑。我想先比较几个 CPU 然后再讨论 ISA 会很有趣。
比较几个 CPU 以及它们可以做什么以及它们如何重叠:
Cortex M0/M0+/M1/M23被认为是Thumb (Thumb-1),可以执行与其他相比受限的2 字节操作码。但是,一些指令,例如mrs
, msr
, bl
, dmb
, dsb
,isb
来自 Thumb-2 并且是4-byte。Cortex M0/M0+/M1 是 ARMv6,而 Cortex M23 是 ARMv8。Thumb-1 指令在 ARMv7 中进行了扩展,因此可以说 ARMv8 Cortex M23 支持更完整的 Thumb-1(it
指令除外),而 ARMv6 Cortex M0/M0+ 仅支持 ISA 的一个子集(特别缺少它们it
,cbz
并且cbnz
指示)。我可能是错的(如果这不对,请纠正我),但注意到一些有趣的事情,只有我看到的完全支持 Thumb-1 的 CPU 是已经支持 Thumb-2 的 CPU,我不知道只有 Thumb-1 CPU 支持 100% 的 Thumb-1。我认为这是因为it
可以将其视为 Thumb-2 操作码,它是 2 字节的,本质上是添加到 Thumb-1 中的。在 Thumb-1 CPU 上,4 字节操作码可以被视为两个 2 字节来表示 4 字节操作码。
Cortex M3/M4/M7/M33/M35P/M55可以执行2字节和4字节操作码,都是Thumb-1和Thumb-2,支持全套ISA。2 字节和 4 字节操作码混合更均匀,而上面的 Cortex M0/M0+/M1/M23 大部分时间都偏向于使用 2 字节操作码。Cortex M3/M4/M7 是 ARMv7,而 Cortex M33/M35P/M55 是 ARMv8。
Cortex A/R可以接受ARM 和 Thumb操作码,因此有2-byte 和 4-byte。为了在模式之间切换,PC 需要偏移一个字节(强制未对齐),这可以通过例如bx
设置 的T
位CPSR
并根据地址的最低位切换模式的分支指令来完成。这很好用,例如,当调用子程序时,PC(及其模式)被保存,然后在子程序中它可以切换到 Thumb 模式,但是当从 Thumb 模式返回时,它将恢复 PC(及其 T 位)和毫无问题地切换回调用者(ARM 或 Thumb 模式)。
ARM7仅支持ARMv3 4 字节ISA
ARM7T支持Thumb-1 和 ARM ISA(2 字节和 4 字节)
ARM11(ARMv6、ARMv6T2、ARMv6Z、ARMv6K)支持Thumb-1、Thumb-2 和 ARM ISA
我参考的书指出,在 ARMv7和更新版本中,架构从冯诺依曼(数据和指令共享总线)切换到哈佛(专用总线)以获得更好的性能。然而,绝对术语“和更新”是不正确的,因为 ARMv8 更新,但 ARMv8 Cortex M23 是冯诺依曼。
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
寄存器(例如ands
, orrs
, movs
, adds
,subs
指令),而在 Thumb-1 中,s
它始终处于打开状态,并且一直保存CPSR
寄存器。s
在一些较旧的工具链中不需要隐式,但是在统一汇编语言 (UAL) 的努力中,现在需要明确指定s
即使没有选项不使用s
.
Thumb-2是 Thumb 的扩展,可以像 ARM 一样访问所有寄存器,具有 4 字节操作码,与 ARM 相比存在一些差异。在程序集中,Thumb-1 2 字节窄操作码和 Thumb-2 4 字节宽操作码可以强制使用.n
和.w
后缀(示例orr.w
)。ARM 和 Thumb-2 操作码格式/编码不同,它们的功能也不同。可以使用指令的条件执行,但仅当it
(if-then) 指令/块被预先添加。这可以显式或隐含地完成(并由用户背后的工具链完成)。并且混淆实际上可能很好,因为 Arm(该公司)希望它们相似,很多努力都用于统一汇编语言 (UAL),因此为 ARM 制作的汇编文件可以在 Thumb-2 上编译而无需更改。如果我理解正确,则不能 100% 保证,并且在 ARM 程序集无法编译为 Thumb-2 的情况下可能会出现一些边缘情况,这是另一个不完全正确的绝对陈述。例如 ARM7bl
指令可以寻址 +-32MB,而在 Cortex M3 上它只能寻址 +-16MB。与 Thumb-1 相比,这种情况要好得多,在 Thumb-1 中,ARM 程序集更有可能被重写以针对 Thumb-1,而 ARM 到 Thumb-2 的重写不太可能发生。另一个区别是数据处理指令。ARM 和 Thumb-2 都支持 8 位立即数,而 ARM 只能向右旋转位并且只能旋转偶数位,而 Thumb 可以向左旋转以及偶数/奇数位,并且在此之上允许重复的字节模式比如0xXYXYXYXY
,0x00XY00XY
或0xXY00XY00
。因为移位是旋转的,所以左右移位可以通过“溢出”来实现,向一个方向移动太多以至于实际上是向相反方向移动1 << (32 - n) == 1 >> n
所以总而言之,一些 Arm CPU 可以做到:
此信息的参考:ARM 汇编语言编程和架构 Muhammad Ali Mazidi 等人 2016。这本书是在公司名称从 ARM 更改为 Arm 之前编写的,因此有时在引用公司 Arm 和 ARM ISA 时会造成混淆。