为什么16位指令不能访问通用寄存器的高位寄存器

时间:2020-09-30 16:58:17

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

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

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

3 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:5)

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

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

答案 2 :(得分:1)

有关这些核心的唯一实际权威指南是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个寄存器,则每个寄存器仅需要三个位来描述每个字段使用哪个寄存器。

如果要在指令中使用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倾向于最大化指令的数量和可能的功能,而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寄存器指令,它允许您移动高/低,低/高或高/高,技术上是低/低,但是他们更喜欢您使用记录的不同编码。其中之一可以与上述三个寄存器相关的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由于明显的原因而被限制使用(请阅读文档),因此保存和恢复它们存在一定的成本,这是一个折衷方案。)

因此,您应该坚持使用实际的权威指南,而不是声称的事物。

除非那时碰巧在大脑/多维数据集/办公室/会议室中,否则设计师几乎不会在任何地方找到一件事,设计者实施了指令集或特定的指令是“为什么?他们做到了吗? (为什么没有三个寄存器和,或,或,等等)因此,尽管有其他答案,评论和上述内容,这是因为他们想要这样做。而且,如果您需要了解更多信息,您也许可以轻而易举地找到一份工作,也许他们仍然在那里并且可能会和您在一起,但是我希望他们退休。

很久以来,有关各方的答案可能就这些年前的谁说什么以及何时说而有所不同。但是,当尝试采用32位指令集并将子集映射到16位指令以使每单位空间的指令数量加倍时,同时尝试使其足够丰富而又不会大大增加每个任务的指令数量,从而限制了大多数指令对于较低的通用寄存器来说,这样的架构似乎是一个显而易见的设计选择。我将不得不重新审视等效的MIPS,以查看他们所做的事情,我希望他们做同样的事情。同样,我还必须重新访问risc-v和其他任何做过同样事情的人。

了解这是一种设计选择,而不是任何要求。

相关问题