ARM寄存器:
ARM 共有37个寄存器,分为:
l 31个通用寄存器。包括程序计数器PC在内。这些寄存器都是32位的。
l 6个状态寄存器。这些寄存器都是32位寄存器,但目前只使用了其中的12位。
ARM有七种不同的处理器模式。在每一种处理模式中都有一组对应的寄存器组。任意时刻可见的寄存器组包括15个通用寄存器R0~R14,一个或者两个状态寄存器及程序计数器PC。
通用寄存器:
l 未备份寄存器包括R0到R7
l 备份寄存器R8到R14
l 程序计数器PC即R15
对于未备份寄存器来说,在所有的处理器模式下指的都是同一个物理寄存器。
对于备份寄存器来说每个寄存器对应不同的物理寄存器。中断模式下R8和R9分别记为R8_fiq,R9_fiq,当在用户模式下时为R8_usr,R9_usr。
R14又称连接寄存器LR.
程序状态寄存器
CPSR(当前程序状态寄存器)可以在任何处理模式下被访问,它包含了条件标志位,中断禁止位,当前处理器模式标志以及其他的一些控制和状态位。
每一种处理模式下都有一个专用的物理状态寄存器称为SPSR(备份程序状态寄存器)。
ARM体系的存储空间:
ARM体系使用单一的平板地址空间。该地址空间的大小为2^32个八位字节。这些字节单元的地址是一个无符号的32位数值,取值范围为0到2^32-1。
ARM的地址空间也可以看做是2^30个32位的字单元,这些字单元的地址可以被4整除。(只是将最开始的地址八位数据所在的单元作为首地址,总共存了32位数据)。地址为A的字数据包括地址为A,A+1,A+2,A+3 四个字节单元内容。
ARM的地址空间也可以看做是2^31个16位的半字单元,这些字单元的地址可以被2整除。(只是将最开始的地址八位数据所在的单元作为首地址,总共存了16位数据)。地址为A的字数据包括地址为A,A+1两个字节单元内容。
ARM的存储格式:
大小端存储模式。
ARM指令分类及其寻址方式:
ARM指令集可以分为6类:
u 跳转指令
u 数据处理指令
u 程序状态寄存器PSR传输指令
u Load/Store指令
u 协处理器指令
u 异常中断产生指令
ARM指令字长为固定的32位。ARM指令的长度都是32bit,其编码格式为:
Bit31---bit28
其中Bit31到bit28是条件码,也就说要满足什么样的条件才能执行该指令。否则是默认无条件执行。无条件执行对应的条件码是1110。有时候,我们调试的时候,查看指令存储器中的二进制表示的指令,如果bit31到bit28这个域的值如果是1110,那么就说明,对应的这条指令就是无条件执行的指令。
Bit27---bit25
bit27到bit25,这三个bit位的数字,它只是表明当前这条指令是执行什么操作的指令。
Opcode
这是表示指令码。写代码的时候,用的是助记符,实际上机器内部,它看到的是二进制指令码。
S
S位表示的是,是否会影响到CPSR的值。CPSR(当前程序状态寄存器)。
Rn和Rd
Rn和Rd,就是源寄存器和目标寄存器了。不过《ARM体系结构与编程》书中,把源操作数叫做第1操作数,或第2操作数。,这个指令码格式里面,给这两个寄存器Rn和Rd都是分配4个bit。知道为什么这么设计了吧?因为通用寄存器总共就16个,4个bit足够。
Shift-operand
最低12bit是shifer_operand,这个表示第2个操作数。
ARM指令的语法格式:
<opcode>{<cond>}{S} <Rd>, <Rn>{,< shifter-operand/operand2>}
<opcode> 是助记符,如ADD表示算术加操作指令。
{<>} 表示执行的条件
{S} 决定指令操作是否受CPSR影响
<Rd> 表示目标寄存器
<Rn> 表示含第一个操作数的寄存器
<shifter-operand> 表示第二个操作数
格式说明:
u S:可选后缀;若指定S,则根据指令执行结果更新CPSR的条件码NZCV;
u Rd:目标操作数的寄存器,可以是R0~R15中任意一个;
u Rn:源操作数的寄存器,可以是R0~R15中任意一个;
u Operand2:第二个操作数;
u <>:表示<>内的部分是必须的,如<Opcode>是指令助记符,Opcode是必须书写的;
u {}:表示{}内的部分是可选的;若不书写,则使用默认条件AL(无条件执行);
u <opcode>、{<cond>}、{S}之间没有任何分隔符;
u 操作数之间可以用“,”、空格或Tab分割;
ADDEQS R0, R1, R2
这条指令不知道啥意思?把后面的EQS拿掉,OK,看出来了吧?ADD,好熟悉的指令助记符!单片机用ADD指令超级经常,表示加法操作嘛!加个EQ,嗯,记起来了,EQ是条件码,表示如果相等就执行该指令?没错!条件码EQ的二进制值为0000,这在《ARM体系结构与编程》一书里的P23页可以查到!S标识位,好了,这个我们之前就说过了,表示是否影响CPSR的值了。好简单的指令,现在我也知道是啥意思了,就是表示先判断条件码,符合,就把(R1 + R2)的值给R0。
这里把ADD这条指令的二进制格式也弄来了,如下所示:
该指令在内存中是以这样的二进制存放的:0B0000 0010 1001 0001 0000 0000 0000 0010。好了,现在知道了ARM指令的编码格式,语法格式,一条指令的简单操作,以及指令在内存里存放的方式。
寻址方式:
立即数寻址
定义:操作数就包含在32位指令编码中,只要取出指令,就可以得到立即数;
显然,定长的32位指令是无法完整表示32位立即数的。在ARM指令集中,合法的立即数是通过8位立即数<Immediate_8>循环右移生成的,因此能够使用的立即数是32位整数的一个子集。
简单立即数寻址实例。
ADDS R0, R0, #1 ; R0←R0 + #1
AND R8, R7, #xF0 ; R8←R7 and #xF0
;#为立即数前缀
;0x或&是16进制前缀;0d是10进制前缀;0b是2进制前缀
合法的立即数<Immediate_EN>定义
<Immediate_EN>的生成方法:
<Immediate_EN>=对<Immerdiate_8>循环右移(2*<rotate_Immediate_4>)位
其中,<Immediate_EN>是32位合法立即数;<Immerdiate_8>是给定的8位立即数;<Rotate_Immediate_4>是指定的4位移位位数,实际移位位数为2*<Rotate_Immediate_4>位。因此,一个能够被合法使用的立即数<Immediate_EN>必须能够的编码为
<Rotate_Immediate_4>< Immediate_8>
其编码长度为12位,使用32位指令编码的低12位。
合法立即数实例
MOV R0, #0x0000F200 ; 编译:E3A00CF2,后12位CF2,0xF200是#F2循环右移2*C=24位。#F2 实际#000000F2其右移24位位后即0XF200
MOV R0, #0x00012800 ; 编译:E3A00B4A,后12位B4A,0x12800是#4A循环右移2*B=22位。
0x12800编码后是B4A,<Rotate_Immediate_4>=B、< Immediate_8>=#4A,< Immediate_8>右循环右移2*B=22位后就是0x12800。
一条ARM指令,只有固定的32位长度。如果这32位都分配给立即数,都用来放立即数,那指令码、条件码、一些寄存器标号就没地方放了。一条ARM指令总共就32bit的空间大小。而且一条ARM指令中,必须有条件码、指令码和一些寄存器标号的存在。所以说,要在这32bit的空间里,分配的立即数的bit位,就只能是有限的bit位。比如说在数据处理指令编码格式中,里面分配给立即数相关的位,只有12个bit位。但是这个12个bit位,我们的目的,是想用它来表示所有的32bit的立即数的。那怎么办?只有12个bit的位,最大只能表示0xFFF的立即数。再大的立即数怎么表示呢?
好,移位操作就可以解决这个问题。这就是为什么在ARM内部,在指令操作前,要先设计一个移位操作的原因。我们只能通过移位,来使得这个ARM指令的立即数取值范围大于0xFFF。但是,这么做也带来了一些弊端。就是我们无法表示所有的32bit的立即数常数。
虽然受到了限制,但是ARM公司仍然决定采用这种受限制的立即数。并且规定,立即数只能由一个8位的常数循环右移偶数位得到。其中循环右移的位数,是由一个4bit位的二进制数的两倍来表示。只有符合这样的立即数,才是合法的立即数。这句话要大家可要好好理解一下哦~学ARM的人都很怕这个地方,嘿嘿,如果你理解好了,那你就牛了,绝对的。
OK,把这句话转换成公式吧,这么表示:
立即数 = 8位常数循环右移(2 × 4bit位二进制数)
但是有一种情况令我很郁闷!立即数通过某个8位常数循环移动来构造出来,可能有多种构造方法。比如《ARM体系结构与编程》里面,提到立即数0X3F0,是合法的立即数,它可以通过0x3F循环右移28次得到,也可以通过0XFC循环右移30次得到。那么,这不就有歧义了吗?ARM只好说,那ARM汇编编译器会选择默认选择一种编码方式来的,OK,这种编码方式的规则就是:
当立即数数值在0和0XFF范围时,立即数就等于8位常数。其他情况下,汇编编译器会选择数值最小的4位二进制来进行编码,构造立即数。
另外,这里要强调,在立即数寻址中,操作数本身直接就在指令中给出,我们取出这个指令,也就获得了操作数。所以能加快执行的效率。
下面举个例子,大家对立即数怎么构造出来就很理解了!这个例子是个代码段:
MOV R0, #0X0000F200
MOV R1, #0X00110000
MOV R4, #0X00012800
上面的指令经过汇编后得到的二进制编码为: