https://www.cnblogs.com/lifexy/p/7363208.html 简介: ARM指令中多数据传输共有两种: LDM:(load much)多数据加载,将地址上的值加载到寄存器上 STM:(store much)多数据存储,将寄存器的值存到地址上 主要用途:现场保护、数据复制、参数传送等,共有8种模式(前面4种用于数据块的传输,后面4种是堆栈操作)如下:
(1)IA:(Increase After) 每次传送后地址加4,其中的寄存器从左到右执行,例如:STMIA R0,{R1,LR} 先存R1,再存LR (2)IB:(Increase Before)每次传送前地址加4,同上 (3)DA:(Decrease After)每次传送后地址减4,其中的寄存器从右到左执行,例如:STMDA R0,{R1,LR} 先存LR,再存R1 (4)DB:(Decrease Before)每次传送前地址减4,同上 (5)FD: 满递减堆栈 (每次传送前地址减4) (6)FA: 满递增堆栈 (每次传送后地址减4) (7)ED: 空递减堆栈 (每次传送前地址加4) (8)EA: 空递增堆栈 (每次传送后地址加4) 注意:其中在数据块的传输中是STMMDB和LDMIA对应,STMMIA和LDMDB对应 而在堆栈操作是STMFD和LDMFD对应,STMFA和LDMFA对应
格式:
LDM{cond} mode Rn{!}, reglist{^} STM{cond} mode Rn{!}, reglist{^}
其中
Rn:基址寄存器,装有传送数据的起始地址,Rn不允许为R15; !:表示最后的地址写回到Rn中; reglist:可包含多于一个寄存器范围,用“,”隔开,如{R1,R2,R6-R9},寄存器由小到大顺序排列; ^:不允许在用户模式和系统模式下运行
数据块的传输-实例:
Ldr R1,=0x10000000 //传送数据的起始地址0x10000000 LDMIB R1!,{R0,R4-R6} //从左到右加载,相当于 LDR R0,10000004 LDR R4,10000008... ... /*传送前地址加+4, 所以地址加4,R0=0X1000004地址里的内容, 地址加4,R4=0X10000008地址里的内容, 地址加4,R5=0X1000000C地址里的内容, 地址加4,R6=0X10000010 地址里的内容, 由于!, 最后的地址写回到R1中,R1=0X10000010 */ Ldr R1,=0x10000000 //传送数据的起始地址0x10000000 LDMIA R1!,{R0,R4-R6} //从左到右加载,相当于 LDR R0,10000000 LDR R4,10000004... ... /*传送后地址加+4, 所以R0=0X10000000地址里的内容,地址加4, R4=0X10000004地址里的内容,地址加4, R5=0X10000008地址里的内容,地址加4, R6=0X1000000C 地址里的内容,地址加4, 由于!,最后的地址写回到R1中,所以R1=0X10000010 */ LDR R1,=0x10000000 //传送数据的起始地址0x10000000 LDR R4,=0X10 LDR R5,=0X20 LDR R6,=0X30 STMIB R1,{R4-R6} //从左到右加载,相当于STR [R4],0X10000004 STR [R5],0X10000008 ..... /*传送前地址加+4,所以0X10000004地址=0X10,0X10000008地址=0X20,0X1000000C地址=0X30 */ Ldr R1,=0x10000000 //传送数据的起始地址0x10000000 LDR R4,=0X10 LDR R5,=0X20 LDR R6,=0X30 STMIA R1!,{R4-R6 } /*传送后地址加+4,所以0X10000000地址=0X10,0X10000004地址=0X20,0X10000008地址=0X30,由于!,最后的地址写回到R1中,所以R1=0X1000000C */ 中断实例(利用STMDB和LDMIA保护现场,然后通过LR寄存器返回) 1.先设置栈sp,用于后面使用stmdb存储寄存器数据 2.当产生异常时,便进入中断: sub lr, lr, #4 //首先将lr-4,因为arm流水线,lr=当前pc+8,由于pc+4段没有执行,所以lr=(当前pc+8)-4; stmdb sp!, { r0-r12,lr } //每次传送前-4,由于递减,所以从右往左存储寄存器 //所以sp-4=lr,sp-8=r12,... sp-56=r0; 由于!,所以最后的地址写回到sp中,sp=sp-56; ldr lr, =int_return //设置返回地址 ldr pc, =EINT_Handle //进入中断服务函数,如果中途返回就会调用pc=lr,即可执行int_return; int_return: ldmia sp!, { r0-r12,pc }^ //每次传送后+4,所以从左往右加载数据到寄存器 //所以r0=sp, r1=sp+4,...pc=sp+52;由于!,所以最后地址写回到sp中,sp=sp+56; //此时,sp=sp+56就等于最初栈顶值,pc=lr,然后返回到异常发生前的相应位置继续执行。 //^ ^表示将spsr的值复制到cpsr,因为异常返回后需要恢复异常发生前的工作状态
STR R1,[R0] ;将R1中的内容传输到R0中的数所指定的地址的内存中去 LDR R1,=0xE0000000 ;R1=0xE0000000 LDR R1,0xE0000000 ;将内存中地址为0xE0000000的内容载入到R1 LDR R1,[R0] ;将R0中的数所指定的地址的内容传输到R1
1,ldr加载指令
LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0。 LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0。 LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0。 LDR R0,[R1,R2]!;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1。 LDR R0,[R1,#8]! ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1。 LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1。 LDR R0,[R1,R2,LSL#2]! ;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。 LDR R0,[R1],R2,LSL#2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
2,ldr伪指令 LDR伪指令的形式是“LDR Rn,=expr”。
COUNT EQU 0x40003100 …… LDR R1,=COUNT MOV R0,#0 STR R0,[R1] COUNT是我们定义的一个变量,地址为0x40003100。 这中定义方法在汇编语言中是很常见的,如果使用过单片机的话,应该都熟悉这种用法。 LDR R1,=COUNT是将COUNT这个变量的地址,也就是0x40003100放到R1中。 MOV R0,#0是将立即数0放到R0中。 最后一句STR R0,[R1]是一个典型的存储指令, 将R0中的值放到以R1中的值为地址的存储单元去。 实际就是将0放到地址为0x40003100的存储单元中去。 可见这三条指令是为了完成对变量COUNT赋值。 用三条指令来完成对一个变量的赋值,看起来有点不太舒服。 这可能跟ARM的采用RISC有关。
跳转指令用于实现程序流程的跳转,在 ARM 程序中有两种方法可以实现程序流程的跳转:
(1) 使用专门的跳转指令。 (2) 直接向程序计数器 PC 写入跳转地址值。 通过向程序计数器 PC 写入跳转地址值,可以实现在 4GB 的地址空间中的任意跳转,在跳转之前结合使用 MOV LR , PC 等类似指令,可以保存将来的返回地址值,从而实现在 4GB 连续的线性地址空间的子程序调用。
ARM 指令集中的跳转指令可以完成从当前指令向前或向后的 32MB 的地址空间的跳转,包括以下 4 条指令:
B 指令的格式为: B{条件} 目标地址 B 指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继 续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后32MB 的地址空间)。以下指令: B Label ;程序无条件跳转到标号 Label 处执行
CMP R1 ,# 0 ;当 CPSR 寄存器中的 Z 条件码置位时,程序跳转到标号 Label 处执行 BEQ Label
BL 指令的格式为: BL{条件} 目标地址 BL 是另一个跳转指令,但跳转之前,会在寄存器R14 中保存PC 的当前内容, 因此,可以通过将R14 的内容重新加载到PC 中,来返回到跳转指令之后的那个指令处执行。 该指令是实现子程序调用的一个基本但常用的手段。以下指令: BL Label ;当程序无条件跳转到标号 Label 处执行时,同时将当前的 PC 值保存到 R14 中
BLX 指令的格式为: BLX 目标地址 BLX 指令从ARM 指令集跳转到指令中所指定的目标地址,并将处理器的工作状态有ARM 状态切换到Thumb 状态, 该指令同时将PC 的当前内容保存到寄存器R14 中。 因此,当子程序使用Thumb 指令集,而调用者使用ARM 指令集时,可以通过BLX 指令实现子程序的调用和处理器工作状态的切换。 同时,子程序的返回可以通过将寄存器R14 值复制到PC 中来完成。
BX 指令的格式为: BX{条件} 目标地址 BX 指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM 指令,也可以是Thumb指令。
堆栈指针r13(SP) 连接寄存器r14(LR) 程序计数器r15(PC)
https://blog.csdn.net/u012357001/article/details/88989827?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0.highlightwordscore&spm=1001.2101.3001.4242.1
MCR 指令的格式为: MCR{条件} 协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2。 MCR 指令用于将ARM 处理器寄存器中的数据传送到协处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1 和协处理器操作码2 为协处理器将要执行的操作,源寄存器为ARM 处理器的寄存器,目的寄存器1 和目的寄存器2 均为协处理器的寄存器。 指令示例: MCR P3,3,R0,C4,C5,6;该指令将 ARM 处理器寄存器 R0 中的数据传送到协处理器 P3 的寄存器 C4 和 C5 中。
MRC 指令的格式为: MRC{条件} 协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2。 MRC 指令用于将协处理器寄存器中的数据传送到ARM 处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1 和协处理器操作码2 为协处理器将要执行的操作,目的寄存器为ARM 处理器的寄存器,源寄存器1 和源寄存器2 均为协处理器的寄存器。 指令示例: MRC P3,3,R0,C4,C5,6;该指令将协处理器 P3 的寄存器中的数据传送到 ARM 处理器寄存器中. 再举个例子: mrc p15,0,r0,c1,c0,0;将协处理器p15的寄存器中的数据传送到ARM处理器的寄存器r0中,其中1是协处理器操作码1,0是协处理器操作码2,c1存放第一个操作数的协处理器寄存器,c0存放第二个操作数的协处理器寄存器
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。