ARM寄存器及其汇编指令
ARM处理器
第一款RISC(精简指令集)微处理器,(arm)32位设计,但配有16位指令集(thumb)
32位和16位可以相互调用,且开销几乎为0
使用大量寄存器,功耗低,效率高
ps:具体发展,系列之类请参考百度百科:https://baike.baidu.com/item/arm/5907
arm寄存器
arm包括37个寄存器,都是32位
31个通用寄存器,6个状态寄存器
arm有7种处理器模式,每个模式中有一组相应的寄存器
在任何一种处理器模式下可见的寄存器包括15个通用寄存器(r0-r14),一个或者两个状态寄存器,程序技术器(pc)
所有寄存器中,有些是各模式公用的物理寄存器,有些是某个模式独立拥有的物理寄存器
七个处理器模式: 用户模式(User),快速中断模式(FIQ),普通中断模式(IRQ),管理模式(Svc),数据访问中止模
(Abort),未定义指令中止模式(Und),系统模式(Sys)
寄存器用途
r0 - r3:传参
r4 - r11:保存局部变量,但在thumb(16位程序)中,通常只能用r4-r7来保存局部变量
r12:ip寄存器
r13:栈帧,即sp
r14:lr,被称为连接寄存器,用于保存子程序以及中断的返回地址
r15:程序计数器,即pc,但由于arm使用的是三级流水线结构,所以我们读取正确的pc的值之后应该在该值基础上加八个字节,即指向pc下两条指令的地址
ps:关于三级流水线,另一片相关文章会具体解释
CPSR:当前程序状态寄存器,在任何模式下可以被访问。包含条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位。CPSR在用户编程时由于存储条件码。
SPSR:每一种模式下都有一个状态寄存器SPSR,用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。用户模式和系统模式不是异常状态,所以没有SPSR,在这两种模式下访问SPSR,将产生不可预知的后果。
CPSR详解:
ps:长度为32
cpsr包括条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位
通过上图就可以理解cpsr_cxsf的意思了
条件码标志
N:结果是有符号的二进制补码情况下,结果为负的话N=1,结果为非负的话N=0
Z:结果如果为零的话Z=1,结果非零的话Z=0
C:有多种情况
对于加法指令(包括比较指令CMN),产生进位的话C=1,否则C=0。
对于减法指令(包括比较指令CMP),如果产生借位,则C=0;否则C=1。
对于有移位操作的非法指令,C为移位操作中最后移出位的值。
对于其他指令,C通常不变。
ps:比较指令CMN与CMP其实才是算数指令,之后会有详解
V:对于加减法指令,在操作数和结果是有符号的整数时,如果发生溢出,则V=1;如果无溢出发生,则V=0;对于其他指令,V通常不发生变化
ARM指令集
指令格式
{ } {S} , {, }
<>
内是必须项,{}
内是可选项,不写
代表无条件执行
opcode 指令助记符,如LDR,STR 等
cond 执行条件,如EQ,NE 等
S 是否影响CPSR 寄存器的值,书写时影响CPSR,否则不影响
Rd 目标寄存器
Rn 第一个操作数的寄存器
operand2 第二个操作数
储存器访问指令
ARM 处理是加载/存储体系结构的典型的RISC处理器
对存储器的访问只能使用加载和存储指令实现
ARM 的加载/存储指令是可以实现字、半字、无符/有符字节操作
批量加载/存储指令可实现一条指令加载/存储多个寄存器的内容
SWP指令是一条寄存器和存储器内容交换的指令,可用于信号量操作等
ARM 处理器是冯.诺依曼存储结构,程序空间、RAM 空间及IO 映射空间统一编址,除对对RAM 操作以外,对外围IO、程序数据的访问均要通过加载/存储指令进行
下图给出ARM存储访问指令表
LDR/STR
LDR{cond}{T} Rd,<地址>;
STR{cond}{T} Rd,<地址>;
LDR从内存中读取数据放入寄存器,STR用于将寄存器内的数据放到内存
LDR R2, [R7,#0x10+var_C] 将
R7 + 0x10+var_C
地址的数据放到R2STR R3, [R7,#0x10+var_4] 将R3的数据储存在
R7 + 0x10+var_4
{T}为可选项,若指令有T,那么即使处理器是在特权模式下,存储系统也将访问看成是处理器是在用户模式下
T在用户模式下无效,不能与前索引偏移一起使用T
LDR Rd,[Rn] 零偏移,将Rn的值作为内存地址
LDR Rd,[Rn,#0x04]! 前索引偏移,将Rn+0x04地址的值放到Rd,并且
更新Rn
的值为Rn = Rn + 0x04,如果没有后边感叹号,则Rn不更新LDR Rd,label ; 程序相对偏移,label 为程序标号,label 必须是在当前指令的±4KB范围内
LDR Rd,[Rn],#0x04 后索引偏移,将Rn中的地址的数据加载到Rd中,然后将Rn更新Rn = Rn + 0x04
ps:前索引偏移就是在索引前偏移,看有无!决定时候更新寄存器的内容。后索引偏移就是在索引后偏移,索引时并不偏移,索引后更新寄存器内容
LDM/STM
LDM{cond}<模式> Rn{!},reglist{^}
STM{cond}<模式> Rn{!},reglist{^}
LDM 加载多个寄存器,STM储存多个寄存器
主要用途是现场保护、数据复制、参数传送等
其模式有8种,如下所列:(前面4 种用于数据块的传输,后面4 种是堆栈操作)
(1) IA:每次传送后地址加4
(2) IB:每次传送前地址加4
(3) DA:每次传送后地址减4
(4) DB:每次传送前地址减4
(5) FD:满递减堆栈
(6) ED:空递增堆栈
(7) FA:满递增堆栈
(8) EA:空递增堆栈
寄存器Rn为基址寄存器,装有传送数据的初始地址,Rn 不允许为R15;缀!
表示最后的地址写回到Rn中
寄存器列表reglist 可包含多于一个寄存器或寄存器范围,使用“,”分开,如{R1,R2,R6-R9},寄存器排列由小到大排列
^
后缀不允许在用户模式呈系统模式下使用,若在LDM 指令用寄存器列表中包含有PC 时使用,那么除了正常的多寄存器传送外,将SPSR 拷贝到CPSR 中,这可用于异常处理返回
使用^
后缀进行数据传送且寄存器列表不包含PC时,加载/存储的是用户模式的寄存器,而不是当前模式的寄存器
LDMIA R0!,{R3-R9} ;加载R0 指向的地址上的多字数据,保存到R3~R9中,R0 值更新
STMIA R1!,{R3-R9} ;将R3~R9 的数据存储到R1 指向的地址上,R1值更新
STMFD SP!,{R0-R7,LR} ;现场保存,将R0~R7、LR入栈
LDMFD SP!,{R0-R7,PC}^;恢复现场,异常处理返回
SWP 寄存器和存储器交换指令
SWP{cond}{B} Rd,Rm,[Rn]
SWP指令用于将一个内存单元(该单元地址放在寄存器Rn中)的内容读取到一个寄存器Rd中,同时将另一个寄存器Rm 的内容写入到该内存单元中
B 为可选后缀,若有B,则交换字节,否则交换32 位字:Rd 为数据从存储器加载到的寄存器;Rm的数据用于存储到存储器中,若Rm 与Rn 相同,则为寄存器与存储器内容进行交换;Rn 为要进行数据交换的存储器地址,Rn 不能与Rd 和Rm 相同
SWP R1,R1,[R0] ; 将R1 的内容与R0 指向的存储单元的内容进行交换
SWP R1,R2,,[R0] ; 将R0 指向的存储单元内容读取一字节数据到R1中(高24 位清零) ; 并将R2 的内容写入到该内存单元中(最低字节有效)
ARM 数据处理指令
MOV 数据传送指令
MOV{cond}{S} Rd,operand2
将8 位立即数或寄存器(operant2)传送到目标寄存器Rd,可用于移位运算等操作
MOV R1#0x10 ;R1=0x10
MOV R0,R1 ;R0=R1
MOVS R3,R1,LSL #2 ;R3=R1<<2,并影响标志位
MOV PC,LR ;PC=LR ,子程序返回
MVN 数据非传送指令
MVN{cond}{S} Rd,operand2
将8 位图立即数或寄存器(operand2)按位取反后传送到目标寄存器(Rd),因为其具有取反功能,所以可以装载范围更广的立即数
MVN R1,#0xFF ;R1=0xFFFFFF00
MVN R1,R2 ;将R2 取反,结果存到R1
ADD 加法运算指令
ADD{cond}{S} Rd,Rn,operand2
将operand2 数据与Rn 的值相加,结果保存到Rd 寄存器
ADDS R1,R1,#1 ;R1=R1+1
ADD R1,R1,R2 ;R1=R1+R2
ADDS R3,R1,R2,LSL #2 ;R3=R1+R2<<2
SUB 减法运算指令
SUB{cond}{S} Rd,Rn,operand2
用寄存器Rn 减去operand2。结果保存到Rd 中
SUBS R0,R0,#1 ;R0=R0-1
SUBS R2,R1,R2 ;R2=R1-R2
SUB R6,R7,#0x10 ;R6=R7-0x10
RSB 逆向减法指令
RSB{cond}{S} Rd,Rn,operand2
用寄存器operand2 减法Rn,结果保存到Rd 中
RSB R3,R1,#0xFF00 ;R3=0xFF00-R1
RSBS R1,R2,R2,LSL #2 ;R1=R2<<2-R2=R2×3
RSB R0,R1,#0 ;R0=-R1
ADC 带进位加法指令
ADC{cond}{S} Rd,Rn,operand2
将operand2 的数据与Rn 的值相加,再加上CPSR中的C 条件标志位,结果保存到Rd 寄存器
ADC R1,R1,R3 ;使用ADC 实现64 位加法,R1=R1+R3
SBC 带进位减法指令
SCB{cond}{S}Rd,Rn,operand2
用寄存器Rn 减去operand2,再减去CPSR 中的C条件标志位的非(即若C 标志清零,则结果减去1),结果保存到Rd 中
SBC R1,R1,R3 ;使用SBC 实现64 位减法,R1 = R1 - R3
RSC 带进位逆向减法指令
RSC{cond}{S} Rd,Rn,operand2
用寄存器operand2 减去Rn,再减去CPSR 中的C条件标志位,结果保存到Rd 中
RSC R3,R1,#0 ;使用RSC 指令实现求64 位数值的负数 R3 = 0 -R1
**AND **逻辑与操作指令
AND{cond}{S} Rd,Rn,operand2
将operand2 值与寄存器Rn 的值按位作逻辑与操作,结果保存到Rd中
逻辑与操作,都为1则返回1
ANDS R0,R0,#x01 ;R0=R0&0x01,取出最低位数据
AND R2,R1,R3 ;R2=R1&R3
**ORR **逻辑或操作指令
ORR{cond}{S} Rd,Rn,operand2
将operand2 的值与寄存器Rn的值按位作逻辑或操作,结果保存到Rd 中
ORR R0,R0,#x0F ;将R0 的低4 位置1
MOV R1,R2,LSR #4
ORR R3,R1,R3,LSL #8 ;使用ORR 指令将近R2 的高8位数据移入到R3 低8 位中
**EOR **逻辑异或操作指令
EOR{cond}{S}Rd,Rn,operand2
将operand2 的值与寄存器Rn 的值按位作逻辑异或操作,结果保存到Rd中
EOR R1,R1,#0x0F ;将R1 的低4 位取反
EOR R2,R1,R0 ;R2=R1^R0
EORS R0,R5,#0x01 ;将R5 和0x01 进行逻辑异或,结果保存到R0,并影响标志位
BIC 位清除指令
BIC{cond}{S}Rd,Rn,operand2
将寄存器Rn 的值与operand2 的值的反码按位作逻辑与操作,结果保存到Rd中。
BIC R1,R1,#0x0F ;将R1 的低4 位清零,其它位不变
BIC R1,R2,R3 ;将拭的反码和R2 相逻辑与,结果保存到R1
CMP 比较指令
CMP{cond} Rn,operand2
指令使用寄存器Rn 的值减去operand2 的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行
CMP 指令不保存运算结果
CMP R1,#10 ;R1 与10 比较,设置相关标志位
CMP R1,R2 ;R1 与R2 比较,设置相关标志位
**CMN **负数比较指令
CMN{cond} Rn,operand2
指令使用寄存器Rn 与值加上operand2 的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行
CMN R0,#1 ;R0+1,判断R0 是否为1 的补码,若是Z 置位
CMN 指令与ADDS 指令的区别在于CMN 指令不保存运算结果。CMN指令可用于负数比较,比如CMNR0,#1 指令则表示R0 与-1 比较,若R0 为-(即1 的补码),则Z 置位,否则Z复位。
TST 位测试指令
TST{cond} Rn,operand2
指令将寄存器Rn 的值与operand2 的值按位作逻辑与操作,根据操作的结果更新CPSR中相应的条件标志位(当结果为0时,EQ位被设置),以便后面指令根据相应的条件标志来判断是否执行
TST R0,#0x01 ;判断R0 的最低位是否为0
TST R1,#0x0F ;判断R1 的低4 位是否为0
TST 指令与ANDS 指令的区别在于TST4 指令不保存运算结果。TST指令通常于EQ、NE条件码配合使用,当所有测试位均为0 时,EQ 有效,而只要有一个测试为不为0,则NE 有效。
TEQ 相等测试指令
TEQ{cond} Rn,operand2
指令寄存器Rn 的值与operand2 的值按位作逻辑异或操作,根据操作的结果更新CPSR中相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行
TEQ R0,R1 ;比较R0 与R1 是否相等(不影响V 位和C 位)
TST 指令与EORS 指令的区别在于TST 指令不保存运算结果。使用TEQ进行相等测试,常与EQNE 条件码配合使用,当两个数据相等时,EQ 有效,否则NE 有效。
MUL 32 位乘法指令
MUL{cond}{S} Rd,Rm,Rs
指令将Rm 和Rs 中的值相乘,结果的低32 位保存到Rd中
MUL R1,R2,R3 ;R1=R2×R3
MULS R0,R3,R7 ;R0=R3×R7,同时设置CPSR 中的N位和Z 位
MLA 32 位乘加指令
MLA{cond}{S} Rd,Rm,Rs,Rn
指令将Rm 和Rs 中的值相乘,再将乘积加上第3 个操作数,结果的低32位保存到Rd 中
MLA R1,R2,R3,R0 ;R1=R2×R3+R0
**UMULL ** 64 位无符号乘法指令
UMULL{cond}{S} RdLo,RdHi,Rm,Rs
指令将Rm 和Rs 中的值作无符号数相乘,结果的低32位保存到RsLo 中,而高32 位保存到RdHi 中
UMULL R0,R1,R5,R8 ;(R1、R0)=R5×R8
UMLAL 64 位无符号乘加指令
UMLAL{cond}{S} RdLo,RdHi,Rm,Rs
指令将Rm 和Rs 中的值作无符号数相乘,64 位乘积与RdHi、RdLo相加,结果的低32 位保存到RdLo 中,而高32 位保存到RdHi 中
UMLAL R0,R1,R5,R8;(R1,R0)=R5×R8+(R1,R0)
**SMULL **64 位有符号乘法指令
SMULL{cond}{S} RdLo,RdHi,Rm,Rs
指令将Rm 和Rs 中的值作有符号数相乘,结果的低32位保存到RdLo 中,而高32 位保存到RdHi 中
SMULL R2,R3,R7,R6 ;(R3,R2)=R7×R6
SMLAL 64 位有符号乘加指令
SMLAL{cond}{S} RdLo,RdHi,Rm,Rs
指令将Rm 和Rs 中的值作有符号数相乘,64 位乘积与RdHi、RdLo,相加,结果的低32位保存到RdLo 中,而高32 位保存到RdHi 中
SMLAL R2,R3,R7,R6;(R3,R2)=R7×R6+(R3,R2)
ARM跳转指令
B
B{cond} label
跳转到指定的地址执行程序,跳转到指令B 限制在当前指令的±32Mb 的范围内
B WAITA ;跳转到WAITA 标号处
B 0x1234 ;跳转到绝对地址0x1234 处
**BL **带链接的跳转指令
BL{cond} label
指令将下一条指令的地址拷贝到R14(即LR)链接寄存器中,然后跳转到指定地址运行程序
跳转指令B 限制在当前指令的±32MB 的范围内。BL 指令用于子程序调用
BL DELAY
BX 带状态切换的跳转指令
BX{cond} Rm
跳转到Rm 指定的地址执行程序,若Rm 的位[0]为1,则跳转时自动将CPSR 中的标志T 置位,即把目标地址的代码解释为Thumb代码;若Rm 的位[0]为0,则跳转时自动将CPSR 中的标志T 复位,即把目标地址的代码解释为ARM代码
ADRL R0,ThumbFun+1
BX R0 ;跳转到R0 指定的地址,并根据R0 的最低位来切换处理器状态
BLX
BLX目标地址:跳转,改变状态及保存PC值
ARM 协处理器指令
CDP 协处理器数据操作指令
CDP{cond}coproc,opcodel,CRd,CRn,CRm{,opcode2}
coproc 指令操作的协处理器名。标准名为pn,n 为0~15。
opcodel 协处理器的特定操作码。
CRd 作为目标寄存器的协处理器寄存器。
CRN 存放第1 个操作数的协处理器寄存器。
CRm 存放第2 个操作数的协处理器寄存器。
Opcode2 可选的协处理器特定操作码。
ARM 处理器通过CDP 指令通知ARM 协处理器执行特定的操作。该操作由协处理器完成,即对命令的参数的解释与协处理器有关,指令的使用取决于协处理器。若协处理器不能成功地执行该操作,将产生未定义指令异常中断
CDP p7,0,c0,c2,c3,0 ;协处理器7 操作,操作码为0,可选操作码为0
CDP p6,1,c3,c4,c5 ;协处理器操作,操作码为1
LDC 协处理器数据读取指令
LDC{cond}{L} coproc,CRd,<地址>
L 可选后缀,指明是长整数传送。
coproc 指令操作的协处理器名。标准名为pn,n 为0~15
CRd 作为目标寄存的协处理器寄存器。
<地址> 指定的内存地址
LDC指令从某一连续的内存单元将数据读取到协处理器的寄存器中。协处理器数据的数据的传送,由协处理器来控传送的字数。若协处理器不能成功地执行该操作,将产生未定义指令异常中断
LDC p5,c2,[R2,#4];读取R2+4指向的内存单元的数据,传送到协处理器p5的c2寄存器中
LDC p6,c2,[R1] ;读取是指向的内存单元的数据,传送到协处理器p6的c2 寄存器中
STC 协处理器数据写入指令
STC{cond}{L} coproc,CRd,<地址>
L 可选后缀,指明是长整数传送。
coproc 指令操作的协处理器名。标准名为pn,n 为0~15
CRd 作为目标寄存的协处理器寄存器。
<地址> 指定的内存地址
STC指令将协处理器的寄存器数据写入到某一连续的内存单元中。进行协处理器数据的数据传送,由协处理器来控制传送的字数。若协处理器不能成功地执行该操作,将产生未定义指令异常中断
STC p5,c1,[R0]
STC p5,c1,[Ro,#-0x04]
MCR ARM寄存器到协处理器寄存器的数据传送指令
MCR{cond}coproc,opcodel,Rd,CRn,CRm{,opcode2}
coproc 指令操作的协处理器名。标准名为pn,n 为0~15。
cpcodel 协处理器的特定操作码。
RD 作为目标寄存器。
CRn 存放第1 个操作数的协处理器寄存器
CRm 存放第2 个操作数的协处理器寄存器。
Opcode2 可选的协处理器特定操作码。
MCR 指令将ARM 处理器的寄存器中的数据传送到协处理器的寄存器中。若协处理器不能成功地执行该操作,将产生未定义指令异常中断
MCR p6,2,R7,c1,c2,
MCR P7,0,R1,c3,c2,1,
MRC 协处理器寄存器到ARM寄存器到的数据传送指令
MRC {cond}coproc,opcodel,Rd,CRn,CRm{,opcode2}
coproc 指令操作的协处理器名。标准名为pn,n为0~15。
opcodel 协处理器的特定操作码。
Rd 作为目标寄存器。
CRn 存放第1 个操作数的协处理器寄存器。
CRm 存放第2 个操作数的协处理器寄存器。
opcode2 可选的协处理器特定操作码。
MRC 指令将协处理器寄存器中的数据传送到ARM 处理器的寄存器中。若协处理器不能成功地执行该操作。将产生未定义异常中断
MRC p5,2,R2,c3,c2
MRC p7,0,R0,c1,c2,1
ARM 杂项指令
SWI 软中断指令
SWI{cond} immed_24
immed_24 24 位立即数,值为0~16777215 之间的整数。
SWI 指令用于产生软中断,从而实现在用户模式变换到管理模式,CPSR保存到管理模式的SPSR中,执行转移到SWI 向量,在其它模式下也可使用SWI 指令,处理同样地切换到管理模式
SWI 0 ;软中断,中断立即数为0
SWI 0x123456 ;软中断,中断立即数为0x123456
使用SWI 指令时,通常使用以下两种方法进行传递参数,SWI 异常中断处理程序就可以提供相关的服务,这两种方法均是用户软件协定。SWI异常中断处理程序要通过读取引起软中断的SWI 指令,以取得24 位立即数。
(A)指令24 位的立即数指定了用户请求的服务类型,参数通过用寄存器传递。
MOV R0,#34 ;设置了功能号为34
SWI 12 ;调用12 号软中断
(B)指令中的24 位立即数被忽略,用户请求的服务类型由寄存器R0 的值决定,参数通过其它的通用寄存器传递。
MOV R0,#12 ;调用12 号软中断
MOV R1,#34 ;设置子功能号为34
SWI 0 ;
在SWI 异常中断处理程序中,取出SWI 立即数的步骤为:首先确定引起软中断的SWI指令是ARM指令还时Thumb 指令,这可通过对SPSR 访问得到:然后要取得该SWI 指令的地址,这可通过访问LR 寄存器得到:接着读出指令,分解出立即数。
读出SWI 立即数:
T_bit EQU 0x20
SWI_Hander
STMFD SP!,{R0_R3,R12,LR} ;现场保护
MRS R0,SPSR ;读取SPSR
STMFD SP!,{R0} ;保存SPSR
TST R0,#T_bit ;测试T标志位
LDRNEH R0,[LR,#-2] ;若是Thumb指令,读取指令码(16 位)
BICNE R0,R0,#0xFF00 ;取得Thumb 指令的8 位立即数
LDREQ R0,[LR,#-4] ;若是ARM 指令,读取指令码(32 位)
BICNQ R0,R0,#0xFF00000 ;取得ARM 指令的24 位立即数
…
LDMFD SP!,{R0-R3,R12,PC}^ ;SWI 异常中断返回
MRS 读状态寄存器指令
MRS{cond} Rd ,psr
Rd 目标寄存器。Rd 不允许为R15。
psr CPSR 或SPSR
在ARM 处理器中,只有MRS 指令可以状态寄存器CPSR或SPSR读出到通用寄存器中
MRS 指令读取CPSR,可用来判断ALU 的状态标志,或IRQ、FIQ中断是否允许等;在异常处理程序中,读SPSR 可知道进行异常前的处理器状态等。MRS 与MSR 配合使用,实现CPSR 或SPSR 寄存器的读—修改—写操作,可用来进行处理器模式切换(),允许/禁止IRQ/FIQ中断等设置。另外,进程切换或允许异常中断嵌套时,也需要使用MRS 指令读取SPSR 状态值。保存起来
MRS R1,CPSR ;将CPSR状态寄存器读取,保存到R1 中
MRS R2,SPSR ;将SPSR状态寄存器读取,保存到R2 中
使能IRQ 中断例程:
ENABLE_IRQ
MRS R0,CPSR
BIC R0。R0,#0x80
MSR CPSR_c,R0
MOV PC,LR
禁能IRQ 中断例程:
DISABLE_IRQ
MRS R0,CPSR
ORR R0,R0,#0x80
MSR CPSR_c,R0
MOV PC,LR
MSR 写状态寄存器指令
MSR{cond} psr_fields,#immed_8r
MSR{cond} psr_fields,Rm
其中: psr CPSR 或SPSR
fields 指定传送的区域。Fields 可以是以下的一种或多种(字母必须为小写):
c 控制域屏蔽字节(psr[7…0])
x 扩展域屏蔽字节(psr[15…8])
s 状态域屏蔽字节(psr[23。…16])
f 标志域屏蔽字节(psr[31…24])
immed_8r 要传送到状态寄存器指定域的立即数,8 位。
Rm 要传送到状态寄存器指定域的数据的源寄存器。
在ARM 处理器中。只有MSR 指令可以直接设置状态寄存器CPSR或SPSR
MSR CPSR_c,#0xD3 ;CPSR[7…0]=0xD3,即切换到管理模式。
MSR CPSR_cxsf,R3 ;CPSR=R3
只有在特权模式下才能修改状态寄存器。
程序中不能通过MSR 指令直接修改CPSR 中的T 控制位来实现ARM 状态/Thumb状态的切换,必须使用BX 指令完成处理器状态的切换(因为BX 指令属转移指令,它会打断流水线状态,实现处理器状态切换)。MRS 与MSR 配合使用,实现CPSR或SPSR 寄存器的读-修改-写操作,可用来进行处理器模式切换、允许/禁止IRQ/FIQ 中断等设置。
堆栈指令实始化例程:
INITSTACK
MOV R0,LR ;保存返回地址
;设置管理模式堆栈
MSR CPSR_c,#0xD3
LDR SP,StackSvc
;设置中断模式堆栈
MSR CPSR_c,#0xD2
LDR SP,StackIrq
ARM 伪指令
ADR 小范围的地址读取伪指令
ADR{cond} register,exper
register 加载的目标寄存器。
exper 地址表达式。当地址值是非字地齐时,取值范围-255~255 字节之间;当地址是字对齐时,取值范围-1020~1020字节之间。
对于基于PC 相对偏移的地址值时,给定范围是相对当前指令地址后两个字处(因为ARM7TDMI为三级流水线)。
ADR 指令将基于PC 相对偏移的地址值读取到寄存器中。在汇编编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD 指令或SUB 指令来实现该ADR 伪指令的功能,若不能用一条指令实现,则产生错误,编译失败
LOOP MOV R1, #0xF0
…
ADR R2, LOOP ;将LOOP 的地址放入R2
ADR R3, LOOP+4
可以用ADR 加载地址,实现查表:
…
ADR R0,DISP_TAB ;加载转换表地址
LDRB R1,[R0,R2] ;使用R2作为参数,进行查表
…
DISP_TAB
DCB0Xc0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90
ADRL 中等范围的地址读取伪指令
ADR{cond} register,exper
register 加载的目标寄存器。
expr 地址表达式。当地址值是非字对齐时,取范围-64K~64K 字节之间;当地址值是字对齐时,取值范围-256K~256K字节之间。
ADRL 指令将基于PC 相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中,比ADR伪指令可以读取更大范围的地址。在汇编编译源程序时,ADRL 伪指令被编译器替换成两个条合适的指令。若不能用两条指令实现ADRL 伪指令功能,则产生错误,编译失败
ADRL R0,DATA_BUF
…
ADRL R1 DATA_BUF+80
…
DATA_BUF
SPACE 100 ;定义100 字节缓冲区
可以且用ADRL 加载地址,实现程序跳转,中等范围地址的加载:
…ADR LR,RETURNI ;设置返回地址
ADRL R1Thumb_Sub+1 ;取得了Thumb 子程序入口地址,且R1 的0 位置1
BX R1 ;调用Thumb子程序,并切换处理器状态
RETURNI
…
CODE16
Thumb_Sub
MOV R1,#10
…
LDR 大范围的地址读取伪指令
LDR{cond} register,=expr/label_expr
register 加载的目标寄存器
expr 32 位立即数。
label_expr 基于PC 的地址表达式或外部表达式。
LDR 伪指令用于加载32 位的立即数或一个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV 或MVN 的范围,则使用MOV 或MVN 指令代替该LDR 伪指令,否则汇编器将常量放入字池,并使用一条程序相对偏移的LDR指令从文字池读出常量
LDR R0,=0x123456 ;加载32 位立即数0x12345678
LDR R0,=DATA_BUF+60 ;加载DATA_BUF 地址+60
…
LTORG ;声明文字池
伪指令LDR 常用于加载芯片外围功能部件的寄存器地址(32 位立即数),以实现各种控制操作加载32位立即数:
…
LDR R0,=IOPIN ;加载GPIO 寄存器IOPIN 的地址
LDR R1,[R0] ;读取IOPIN 寄存器的值
…
LDR R0,=IOSET
LDR R1,=0x00500500
STR R1,[R0] ;IOSET=0x00500500
…
从PC 到文字池的偏移量必须小于4KB。与ARM 指令的LDR 相比,伪指令的LDR的参数有“=”号
NOP 空操作伪指令
NOP 伪指令在汇编时将会被代替成ARM 中的空操作,比如可能为“MOV R0, R0”指令等
使用就单NOP
ARM寻址
立即数寻址
立即数前面有“#”号,并且如果是十六进制数则在“#”后添加“0x”或“&”,二进制数“#”后面加“%”
寄存器间接寻址
操作数的地址在寄存器中
ADD R0,R1,[R2]
基址变址寻址
将寄存器的内容与指令中给出的地址偏移量相加,从而得到一个操作数的有效地址
ADD R0,R1,[R2]
多寄存器寻址
一条指令可以完成多个寄存器值得传递,一条指令传送最多16个通用寄存器的值
LDMIA R0,{R1,R2,R3,R4}
相对寻址
以程序计数器PC的值作为基地址,指令中的地址标号作为偏移量,将两者相加后得到的操作数的有效地址
例如:BL NEXT
ARM堆栈的增长方式
当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(FullStack)
当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(FullStack)
递增堆栈:向高地址方向生长
递减堆栈:向低地址方向生长