Cortex-A7常用汇编指令
本节我们将介绍一些常用的 Cortex-A7汇编指令,如果想系统的了解 Cortex-A7的所有汇
编指令请参考《 ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》的 A4章节。
处理器内部数据传输指令
使用处理器做的最多事情就是在处理器内部来回的传递数据,常见的操作有:
①、将数据从一个寄存器传递到另外一个寄存器。
②、将数据从一个寄存器传递到特殊寄存器,如 C PSR 和 S PSR 寄存器。
③、将立即数传递到寄存器。
数据传输常用的指令有三个: MOV、 MRS和 MSR,这三个指令的用法如表 7.2.1.1所
示:
指令 目的 源 描述
MOV
R0
R1
将
R1里面的数据复制到 R0中。
MRS
R0
CPSR
将特殊寄存器
CPSR里面的数据复制到 R0中。
MSR
CPSR
R1
将
R1里面的数据复制到特殊寄存器 CPSR里中。
表 7.2.1.1 常用数据传输指令
分别来详细的介绍一下如何使用这三个指令:
1、 MOV指令
MOV指令用于将数据从一个寄存器拷贝到另外一个寄存器,或者将一个立即数传递到寄
存器里面,使用示例如下:
MOV R0 R1 @将寄存器 R1中的数据传递给 R0,即 R0=R1 MOV R0, #0X12 @将立即数 0X12传递给 R0寄存器,即 R0=0X12
2、 MRS指令
MRS指令用于将特殊寄存器 (如 CPSR和 SPSR)中的数据传递给通用寄存器,要读取特殊
寄存器的数据只能使用 MRS指令!使用示例如下:
MRS R0, CPSR @将特殊寄存器 CPSR里面的数据传递给 R0,即 R0=CPSR
3、 MSR指 令
MSR指令和 MRS刚好相反, MSR指令用来将普通寄存器的数据传递给特殊寄存器,也就
是写特殊寄存器,写特殊寄存器只能使用 MSR,使用示例如下
MSR CPSR, R0 @将 R0中的数据复制到 CPSR中,即 CPSR=R0
存储器访问指令
ARM不能直接访问存储器,比如 RAM中的数据, I.MX6UL中的寄存器就是 RAM类型
的,我们用汇编来配置 I.MX6UL寄存器的时候需要借助存储器访问指令,一般先将要配置的值
写入到 Rx(x=0~12)寄存器中,然后借助存储器访问指令将 Rx中的数据写入到 I.MX6UL寄存器分别来详细的介绍一下如何使用这两个指令:
1、 LDR指令
LDR主要用于从存储加载数据到寄存器 Rx中, LDR也可以将一个立即数加载到寄存器 Rx中, LDR加载立即数的时候要使用“ “=”,而不是 “#”。在嵌入式开发中 LDR最常用的就是读
取 CPU的寄存器值,比如 I.MX6UL有个寄存器 GPIO1_GDIR,其地址为 0X0209C004,我们
现在要读取这个寄存器中的数据,示例代码如下:
示例代码7.2.2.1 LDR指令使用 1 LDR R0, =0X0209C004 @将寄存器地址0X0209C004加载到R0中,即R0=0X0209C004 2 LDR R1, [R0] @读取地址0X0209C004中的数据到R1寄存器中
上述代码就是读取寄存器 GPIO1_GDIR中的值,读取到的寄存器值保存在 R1寄存器中,
上面代码中 offset是 0,也就是没有用到 offset。
2、 STR指令
LDR是从存储器读取数据, STR就是将数据写入到存储器中,同样以 I.MX6UL寄存器
GPIO1_GDIR为例,现在我们要配置寄存器 GPIO1_GDIR的值为 0X20000002,示例代码如下
示例代码7.2.2.2 STR指令使用 1 LDR R0, =0X0209C004 @将寄存器地址0X0209C004加载到R0中,即R0=0X0209C004 2 LDR R1, =0X20000002 @R1保存要写入到寄存器的值,即R1=0X20000002 3 STR R1, [R0] @将R1中的值写入到R0中所保存的地址中
LDR和 STR都是按照字进行读取和写入的,也就是操作的 32位数据,如果要按照字节、
半字进行操作的话可以在指令“ LDR”后面加上 B或 H,比如按字节操作的指令就是 LDRB和
STRB,按半字操作的指令就是 LDRH和 STRH。
压栈和出栈指令
我们通常会在 A函数中调用 B函数,当 B函数执行完以后再回到 A函数继续执行。要想
再 跳回 A函数以后代码能够接着正常运行,那就必须在跳到 B函数之前将当前处理器状态保存
起来 (就是保存 R0~R15这些寄存器值 ),当 B函数执行完成以后再用前面保存的寄存器值恢复
R0~R15即可。保存 R0~R15寄存器的操作就叫做现场保护,恢复 R0~R15寄存器的操作就叫做
恢复现场。在进行现场保护的时候需要进行压栈 (入栈 )操作,恢复现场就要进行出栈操作。压栈
的指令为 PUSH,出栈的指令为 POP PUSH和 POP是一种多存储和多加载指令,即可以一次
操作多个寄存器数据,他们利用当前的栈指针 SP来生成地址, PUSH和 POP的用法如表
处理器的堆栈是向下增长的,使用的汇编代码如下:
PUSH {R0~R3, R12} @将R0~R3 和R12 压栈
压栈完成以后的堆栈如图7.2.3.1 所示:
图7.2.3.1 就是对R0~R3,R12 进行压栈以后的堆栈示意图,此时的SP 指向了0X7FFFFFEC,
假如我们现在要再将LR 进行压栈,汇编代码如下:
PUSH {LR} @将LR 进行压栈
对LR 进行压栈完成以后的堆栈模型如图7.2.3.2 所示:
图7.2.3.2 就是分两步对R0~R3,R12 和LR 进行压栈以后的堆栈模型,如果我们要出栈的话
就是使用如下代码:
POP {LR} @先恢复LR
POP {R0~R3,R12} @在恢复R0~R3,R12
出栈的就是从栈顶,也就是SP 当前执行的位置开始,地址依次减小来提取堆栈中的数据
到要恢复的寄存器列表中。PUSH 和POP 的另外一种写法是“STMFD SP!”和“LDMFD SP!”,
因此上面的汇编代码可以改为:
示例代码7.2.3.1 STMFD和LDMFD指令 1 STMFD SP!,{R0~R3, R12} @R0~R3,R12入栈 2 STMFD SP!,{LR} @LR入栈 3 4 LDMFD SP!, {LR} @先恢复LR 5 LDMFD SP!, {R0~R3, R12} @再恢复R0~R3, R12
STMFD可以分为两部分: STM和 FD,同理 LDMFD也可以分为 LDM和 FD。看到 STM和 LDM有没有觉得似曾相识 (不是 STM32啊啊啊啊 ),前面我们讲了 LDR和 STR,这两个是
数据加载和存储指令,但是每次只能读写存储器中的一个数据。 STM和 LDM就是多 存储 和多
加载 ,可以连续的读写存储器中的多个连续数据。
FD是 Full Descending的缩写,即满递减的意思。根据 ATPCS规则 ,ARM使用的 FD类型
的堆栈, SP指向最后一个入栈的数值,堆栈是由高地址向下增长的,也就是前面说的向下增长
的堆栈,因此最常用的指令就是 STMFD和 LDMFD。 STM和 LDM的指令寄存器列表中编号
小的对应低地址,编号高的对应高地址。