【问题标题】:Why can't 16-bit instructions access the high registers of the general purpose registers为什么16位指令不能访问通用寄存器的高位寄存器
【发布时间】:2021-01-16 09:47:14
【问题描述】:

所以现在我读了《ARM Cortex-M3/M4 权威指南》这本书,不明白为什么 16 位指令不能访问高位通用寄存器 R8-R12。

它说实际上很少有人可以访问这些寄存器,但大多数都不能。

【问题讨论】:

  • 如果你的指令只有 16 位长,用 3 位寄存器选择器字段编码 2-3 个操作数寄存器是可行的,但用 4 位寄存器选择器字段编码 2-3 个操作数寄存器是不可行的。
  • 通过缩小操作码来保持紧凑是 Thumb 代码可以提高性能的方式,尤其是在总线受限的机器上。
  • 在阅读这样的书之前,您需要对 arm(任何东西)的实际权威指南,这是所讨论核心的架构参考手册和技术参考手册(两者都是 armv7-m)和在那里你可以很容易地看到指令的编码没有每个寄存器 4 位的空间。

标签: assembly arm cpu-registers instruction-set thumb


【解决方案1】:

16bits 表示机器码指令只有 16 位来编码信息。 8 个寄存器需要 3 位进行编码。 12 个寄存器需要 4 位进行编码。然后我们需要空间来存放操作码和其他选项,这意味着额外的位可能太多了。

【讨论】:

  • 这假定了一个单寄存器指令,例如负载常数。像算术这样的事情只会变得更糟。
  • 为什么8个寄存器需要3位编码?寄存器都是 32 位的。不要过分判断我刚开始学习架构
  • @SL7Bot:您必须为每个寄存器分配一个唯一的位模式,以便指令解码器知道您在说哪个寄存器。对于 8 个唯一位模式,您至少需要 log_2(8) = 3 位。 “分配唯一的位模式”当然与给每个寄存器一个数字地址并以二进制编码该数字基本相同。同样:要对数字 0-7 进行编码,您需要 3 位。
  • 谢谢,我就是这么想的。现在我明白了
【解决方案2】:

对 8 个寄存器的地址进行编码需要 3 位。对 12 个寄存器的地址进行编码需要 4 位。

如果您有一个 3 寄存器指令,则需要 12 位来对 3 个寄存器进行编码,这样指令就只剩下 4 位了。您最多只能有 16 条指令。

【讨论】:

  • 你仍然可以拥有这 16 种模式中的一个或多个来拥有一堆不使用三个寄存器的子模式。很常见,尤其是手臂...
  • Thumb 指令大多是 2 操作数(例如 x ^= y 而不是指令在 ARM 模式下使用的 z = x ^ y),除了一些非常常见的指令,例如可以使用 3 个不同寄存器的 adds reg, reg, reg在 16 位指令中。但是,是的,在寄存器编号上节省位仍然很重要。
【解决方案3】:

这些核心的唯一实际权威指南是 arm 文档。在阅读任何其他内容或学习指令集之前,您需要拥有文档;在这种情况下,ARMV7-m 的 ARM 架构参考手册以及 cortex-m3 或 cortex-m4 技术参考手册。如果你的书做出了这样的陈述,但没有解释它,那远非确定性。

这在技术上是可行的,但它会占用大量空间,并且可能会破坏尝试 16 位指令的目的(并不意味着 16 位处理器或寄存器或类似的东西,指令本身就是 16 位)。如果您查看已编译的代码以及编译器如何工作,则生成的大量代码使用较低的寄存器或可以这样制作。因此,这是指令集丰富性与指令数量之间的权衡,这与您拥有的寄存器数量无关。

寄存器的大小无关紧要,重要的是寄存器的数量。例如

add r1,r2,r3

您必须在某个地方对哪个寄存器进行编码。注释当然是针对旧的/原始的 16 位指令而不是 thumb2 扩展。

所以你需要一种模式,自然会:

000 r0
001 r1
010 r2
011 r3
100 r4
101 r5
110 r6
111 r7

如果您将自己限制为 8 个寄存器,那么每个寄存器只需要 3 位来描述每个字段使用哪个寄存器。

如果您想在指令中使用 16 个寄存器,那么您需要 4 位:

0000 r0
0001 r1
0010 r2
....
0111 r7
1000 r8
1001 r9
....
1110 r14
1111 r15

如果您的指令集中需要 32 个寄存器(通常不是 ARM thumb),则需要 5 个位:

00000 r0
00001 r1
10000 r16
11111 r31

注意

2 to the power 0 is 1
2 to the power 1 is 2
2 to the power 2 is 4
2 to the power 3 is 8
2 to the power 4 is 16
2 to the power 5 is 32
2 to the power 16 is 65536

等等。

如果你想描述 8 个东西,它需要 3 个比特,如果你想描述 16 个东西,它需要 4 个比特。

16 位意味着可能有 65536 条唯一指令。 ARM 的文档很好地展示了它是如何布置指令集的,它倾向于最大化指令的数量和可能的特性,而 MIPS 则倾向于首先简化解码逻辑,然后才是特性(设计权衡)。

例如,指令的前 6 位是操作码的跳过

00xxxx shift, add, subtract, move, and compare
010000 data processing instructions
010001 special data
01001x ...

等等。根据您下载的 ARM ARM 以各种方式显示。

他们不必实现任何三个寄存器指令,但他们选择了。如果这些指令支持每个操作数的 r0 到 r15,那么这意味着需要 12 位,剩下 4 位用于编码,其中一个或多个用于指示此类指令和其余哪个操作数,您可能会至少清除一个一半可能的指令(一位专用于指示这是不是三寄存器指令)留下 7 个可能的操作,或者,四分之一的指令空间(两位)留下 2 位来选择哪个操作数,使其功能不是很丰富.相反,他们实际所做的是占用 1/4 的指令空间,但为操作数和/或其他功能(立即数等)留下至少 5 位。

所以添加的T1编码是

0001100mmmnnnddd

前两位表示这是哪一组指令,如果你看你会看到第 10 位表示立即数或寄存器 mmm 位是寄存器或 0 到 7 之间的立即数,程序员很多时候想要增加 1 或 2 或一些小数字,并且必须强制执行一条指令并烧毁一个寄存器来放置这个小数字与烧掉一些指令空间的权衡是这里的平衡。

不管怎样,你在这里看到,对于这个指令编码,rm、rn 和 rd 寄存器有 3 位。 (添加 rd,rn,rm),这表明 r0-r7 对这些字段中的任何一个都是可能的。

为了使其更完整,有一个 mov high register 指令,允许您移动高/低、低/高或高/高、技术上的低/低,但他们更喜欢您使用记录中的不同编码。其中之一可以添加与上述三个寄存器相关的 rd,rn,#0。这就是你看到的 gnu 汇编器正在做的事情

.thumb
mov r1,r2
mov r10,r2
mov r1,r11
mov r10,r11
    
00000000 <.text>:
   0:   1c11        adds    r1, r2, #0
   2:   4692        mov r10, r2
   4:   4659        mov r1, r11
   6:   46da        mov r10, r11

要点是有一种方法可以进出高位寄存器,这比进出堆栈更快(无内存周期),因此编译器仍然可以选择使用一个/一些高位寄存器(了解 push/pop由于明显的原因(阅读文档),因此仅限于保存和恢复它们,这是一种权衡)。

因此,您应该坚持对某事的实际权威指南,而不是自称的某事。

除非您碰巧在大脑/立方体/办公室/会议室中,否则您几乎在任何地方都找不到一件事,即设计师实施指令集或特定指令是“为什么“他们做到了吗。 (为什么没有三个寄存器和,异或等)所以尽管有其他答案,cmets 和上述,这是因为他们想要。如果您需要了解更多信息,您也许可以找到一份工作,也许他们还在那里,可能会和您共度时光,但我希望他们会退休。

很久以前,有关各方的答案可能会因多年前谁说什么以及何时说的而异。但是当试图取一个 32 位指令集并将一个子集映射到 16 位指令以使每单位空间的指令数量增加一倍,同时试图足够丰富以不大大增加每个任务的指令数量时,限制了大部分指令对于像这样的体系结构,将其转移到较低的通用寄存器似乎是一个明显的设计选择。我将不得不重新访问等同于 thumb 的 MIPS,看看他们做了什么,我希望他们做同样的事情。同样,我还必须重新访问 risc-v 和任何其他做过同样事情的人。

请理解这是一种设计选择,而不是任何方式的要求。

【讨论】:

    猜你喜欢
    • 2017-06-08
    • 2017-07-15
    • 2013-05-14
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 2011-01-20
    • 2012-06-25
    相关资源
    最近更新 更多