【问题标题】:How many bits do instruction sets have in ARM?ARM中的指令集有多少位?
【发布时间】:2023-01-31 07:45:36
【问题描述】:

在使用 ARM 时,我们通常理解驻留在地址上的数据宽度为 8 位(我希望这个假设是正确的)。

程序计数器如何递增?程序计数器是否每次递增 4?推断指令集都是32位的?我还在某处读到,还有拇指指令集,其中提到了 16 位指令集,这意味着程序计数器每次都应递增 2。

所以,前几天我在看反汇编时发现它并不总是均匀递增。这很令人困惑,因为我一直认为 RISC 处理器(在这种情况下是 ARM)的指令集都是相同的数据宽度。

程序计数器如何知道每次增加什么?通过查看上一条指令的操作码?看起来很复杂。我一直认为程序计数器只是一个按固定值递增的简单计数器(显然我的基本假设是错误的)。

【问题讨论】:

  • 是的,压缩指令是(并行)解码复杂性与 I-cache 占用空间和获取带宽之间的权衡。 ARM 是主流 RISC CPU 中 RICy 最少的(与 RISC 哲学纯度相比,更重视实际工程权衡),但即使是 MIPS 和 RISC-V 也有用于嵌入式使用的压缩指令格式。

标签: arm cpu-architecture instruction-set program-counter risc


【解决方案1】:

听起来您正试图将其复杂化。另请注意,您可以自行下载指令集文档。

ARM 有点通用(MIPS 和 RISC-V 等也是如此)。 ARM 有许多指令集。如果我们考虑传统的 Acorn ARM 时代,它是一条 32 位指令,长度固定。所以程序计数器每条指令移动四个字节。从 ARMv4T 开始,您现在也有了 Thumb 模式,当时它是固定长度的 16 位指令,因此在 Thumb 模式下每条指令两个字节,在 ARM 模式下每个指令四个字节。

带有 ARMv6-m 和 ARMv7-m(最初)的 cortex-ms 固定在拇指模式,没有手臂模式。 “所有拇指变体”指令也是 16 位的,因此每个指令有两个字节。但是一旦你开始解码指令,就会有 thumb2 扩展,由以前无效的 thumb 指令组成,所以你基本上需要再获取两个字节。总共 32 位指令,但长度可变,如 x86 和许多其他指令。 (你获取一个字节,你解码这个字节,也许你需要另一个字节然后解码然后知道你需要获取多少字节)。

我假设人们不知道这一点,但 mips 在他们的一些产品中也有 16 位模式,就像 ARM 你切换模式然后切换回来一样。

ARMv7(不是全尺寸的 cortex-m)也支持 thumb2 指令列表,因此您有正常的 arm 32 位指令,您有 thumb 16 位指令,并且您有 thumb2 扩展,它在 thumb 模式下向特定指令添加另外 16 位。

AARCH64 即 ARMv8 是一个全新的且与前者不兼容的指令集,在此上下文中称为 AARCH32。这些是固定的 32 位指令,所以每个指令有四个字节。

Jazelle 是 JAVA 的东西,JAVA 编译成字节码,所以你解码一个字节并从那里开始。

RISC-V 主要是 32 位指令,但有一种压缩模式,它们是 16 位指令。在 RISC-V 中,32 位和 16 位指令可以背靠背共存,您无需切换模式。每条指令的低位用于确定指令的大小。您可以轻松获取 RISC-V 文档并自行阅读。例如,在 RV32I 中,指令是对齐的。但是,如果您添加压缩的 RV32IC,那么显然,32 位指令可以不对齐。这取决于谁实现这个来选择他们是想一直一次获取 16 个还是一次获取 32 个并且如果不幸的话做额外的工作......

我无法想象任何现代(a 的实现)处理器只会一次将 pc 移动一个字节。非常适合教科书和 6502、8051、z80、x86、家庭作业/学期项目。但这效率低得令人痛苦,而且您使用的处理器运行速度会慢得多。内存甚至没有实现为 8 位字节。您的内部 sram,想想缓存,不是 8 位宽,它们将是 32 位或 64 位宽的倍数,或者 32+奇偶校验或 32+ecc,具体取决于设计。如果你想写一个字节,那么控制器必须读取 32 位值修改其中的 8 个位,然后将其写回。由于所有开销,您无法在 x86 中看到这种性能下降,但您可以在 ARM 和其他高性能处理器中看到它。在 x86 中,您的高速缓存行和高速缓存宽度非常大,并且提取量很大,并且有一些阶段可以解码这个可变长度指令集。

我们可以假设 ARMv1 可能真的有一个用于获取和执行的实际程序计数器。当你开始执行时,程序计数器领先两位,指令集就是围绕它设计的。就像我们假设第一个 MIPS 流水线继续运行并且不能在分支上停止一样,所以您有必须执行的分支影子。没有人应该假设今天的 ARM 处理器的实现有一个用于获取和执行的程序计数器。您可以在周末编写一个模拟器,并且您可能会在某些方面编写类似于一次一条指令模拟器的代码。用于获取下一条指令的“程序计数器”变量,为了执行,您根据模式对程序计数器在执行期间的值进行数学计算。您可能会计算条件分支地址,这是另一个程序计数器。在执行条件分支的某个时刻,您有两个可能的下一个地址,线性下一条指令的地址和分支目标的地址。在获取下一条指令之前,您先选择一条指令。

然后,您需要考虑所有形式的预取和分支预测。添加更多用于同时获取指令的“程序计数器”。

对任何指令集执行相同的操作。

RISC/CISC 在这里无关紧要。对于特定的 XYZ 指令集,这里是该指令集的规则。然后对于每个实现,作者选择如何实现它。有多少东西称为程序计数器或类似程序计数器的功能取决于作者/实现。

看看 x86 以及这些年来发生了多少种不同的实现。有一段时间,他们有两个团队会越级,你可以看到来自同一个团队的团队有时会与那个团队的前一个团队相似,但不一定与另一个团队的团队相似(表现,显然他们都会执行相同的指令集)。

简而言之,这是您从教科书转向现实世界的案例之一。 (教科书5级流水线是另一本)。

像 mips/riscv 中的 r0 和任何处理器中的程序计数器这样的寄存器,你可以访问程序计数器,在没有看到实现的情况下,我们不知道它们是否真的存在于寄存器文件中(如果它是这样实现的)或者它们是否通过 if-then-else 伪造。无论哪种方式,您都必须做额外的工作,否则寄存器文件将获得该值。如果读取了寄存器文件,那么如果它是 pc,则伪造它,否则读取文件。

【讨论】:

  • 嗨 old_timer,感谢您的详细回答,我的思绪从所有细节中旋转 hahhaha。请问在哪里可以阅读更多关于您描述两个团队的 x86 开发的轶事?
猜你喜欢
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-05
  • 2012-05-25
  • 1970-01-01
  • 2022-08-07
相关资源
最近更新 更多