ARM 汇编介绍

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

上面的指令经过汇编后得到的二进制编码为:

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值