ARM处理器指令集
一.数据操作指令集
1.MOV指令
MOV执行结果就是把一个数N送到目标寄存器Rd,其中N可以时寄存器也可以是立即数。
MOV指令多用于设置初始化或者在寄存器间传输数据。
指令的语法格式:
MOV{<c>}{S} <Rd>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标寄存器。如果R15是目标寄存器,将修改程序计数器或标志。这用于被调用的子函数结束后返回到调用代码,方法是把连接寄存器的内容传送到R15。
<shifter_operand>:要传送到Rd寄存器的数据,可以是立即数,寄存器或者移位操作得到。
指令举例:
mov r0,r0; R0=R0 NOP指令 mov r0,r0,lsl#3; R0=R0*8 mov pc,lr;退出到调用者,用于普通函数返回,PC即R15 movs pc,lr;退出到调用者并恢复标志位,用于异常函数返回
MOV指令主要完成以下功能:
-
将数据从一个寄存器传送到另一个寄存器。
-
将一个常数值传送到寄存器中。
-
当PC(R15)用做目标寄存器时,可以实现程序跳转。如“MOV PC,LR”,所以这种跳转可以实现子程序调用及从子程序返回,代替指令“B,BL”。
-
当PC作为目标寄存器且指令中S位被设置时,指令在执行跳转操作的同时,将当前处理器模式的SPSR寄存器的内容复制到CPSR中。可以实现从某些异常中断中返回。
2.MVN指令
MVN是反相传送(Move Negative)指令。它将操作数的反码传送到目的寄存器。
MVN指令多用于向寄存器传送一个负数或者生成位掩码。
MVN指令将shifter_operand表示的数据的反码传送到目标寄存器Rd,并根据操作结果更新CPSR中相应的条件标志位。
指令的语法格式:
MVN{<c>}{S} <Rd>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标寄存器。
<shifter_operand>:要传送到Rd寄存器的数据,可以是立即数,寄存器或者移位操作得到。这是逻辑非而不是算术操作,这个取反的值加1才是它的取负的值。
指令举例:
mvn r0,#4; r0=-5 mvn r0,#0; r0=-1
MVN指令主要完成以下功能:
-
向寄存器中传送一个负数。
-
生成位掩码(Bit Mask)。
-
求一个数的反码。
3.AND指令
AND指令将shifter_operand表示的数值与寄存器Rn的值按位做逻辑与操作,并将结果保存到目标寄存器Rd中,同时根据操作的结果更新CPSR寄存器。
指令的语法格式:
AND{<c>}{S} <Rd>,<Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标寄存器。
<Rn>:第一个操作数寄存器。
<shifter_operand>:要和Rn寄存器做与操作的数据。
指令举例:
and r0,r0,#3 ;保留r0中的0和1位,丢弃其余的位。 and r2,r1,r3 ;r2=r1&r3 ands r0,r0,#0x01 ;r0=r0&0x01,取出最低位数据
4.ORR指令
ORR(Logical OR)为逻辑或者操作指令,它将第2个原操作数shifter_operand的值与寄存器Rn的值按位做“逻辑或”操作,结果保存到Rd中。
指令的语法格式:
ORR{<c>}{S} <Rd>,<Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标寄存器。
<Rn>:第一个操作数。
<shifter_operand>:要和Rn寄存器做逻辑或的数据。
指令举例:
orr r0,r0,#3 ;设置r0中位0和1 orr r0,r0,#0x0f ;将r0的低四位置1 ;使用orr指令将r2的高8位数据移入到r3的低8位中。 mov r1,r2,lsr #4 orr r3,r1,r3,lsl #8
5.BIC位清零指令
BIC(Bit Clear)位清零指令,将寄存器Rn的值与第2个源操作数shifter_operand的值的反码按位做“逻辑与”操作,结果保存到Rd中。
指令的语法格式:
BIC{<c>}{S} <Rd>,<Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标操作数。
<Rn>:第一个操作数。
<shifter_operand>:取反码与Rn做“逻辑与”操作。
指令举例:
bic r0,#0x1011 ;清除r0的位0,4,12位,保持其余的不变 bic r1,r2,r3 ;将r3和r2做“逻辑与”操作,结果保存到r1中
6.EOR指令
EOR(Exclusive OR)指令将寄存器Rn中的值和shifter_operand的值执行按位“异或”操作,并将执行结果存储到目标寄存器Rd中,同时根据指令的执行结果更新CPSR中相应的条件标志位。
指令的语法格式:
EOR{<c>}{S} <Rd>,<Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标寄存器。
<Rn>:第一个操作数。
<shifter_operand>:要和Rn寄存器做异或操作的数据。
指令举例:
eor r0,r0,#3 ;反转r0中的位0和1 eor r1,r1,#0x0f ;将r1的低4位取反 eor r2,r1,r0 ;r2=r1^r0 eors r0,r5,#0x01 ;r0=r5^0x01 影响标志位
7.SUB指令
SUB(Subtract)指令从寄存器Rn中减去shifter_operand表示的数值,并将结果保存到目标寄存器Rd中,并根据指令的执行结果设置CPSR中相应的标志位。
指令的语法格式:
SUB{<c>}{S} <Rd>,<Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标寄存器。
<Rn>:被减数。
<shifter_operand>:减数。
指令举例:
sub r0,r1,r2 ;r0=r1-r2 sub r0,r1,#256 ;r0=r1-256 sub r0,r2,r3,lsl#1 ;r0=r2-(r3<<1)
8.RSB指令
RSB(Reverse Subtract)指令从寄存器shifter_operand中减去Rn表示的数值,并将结果保存到目标寄存器Rd中,并根据指令的执行结果设置CPSR中相应的标志位。
指令的语法格式:
RSB{<c>}{S} <Rd>,<Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标寄存器。
<Rn>:减数。
<shifter_operand>:被减数。
指令举例:
下面的指令序列可以求一个64位数值的负数,64位数放在寄存器R0和R1中,其负数放在R2和R3中。其中R0与R2中放低32位值。
rsbs r2,r0,#0 rsc r3,r1,#0
9.SBC指令
SBC(Subtract with Carry)指令用于执行操作符大于32位时的减法操作。该指令从寄存器Rn中减去shifter_operand表示的数值,再减去寄存器CPSR中C条件标志位的反码[NOT (Carry flag)],并将结果保存到目标寄存器Rd中,并根据指令的执行结果设置CPSR中相应的标志位。
指令的语法格式:
SBC{<c>}{S} <Rd>,<Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标寄存器。
<Rn>:被减数。
<shifter_operand>:减数。
指令举例:
下面的程序使用SBC实现64位减法,(R1,R0)-(R3,R2),结果存放到(R1,R0)。
subs r0,r0,r2 sbcs r1,r1,r3
10.RSC指令
RSC(Reverse Subtract with Carry)指令从从寄存器shifter_operand中减去Rn表示的数值,再减去寄存器CPSR中C条件标志位的反码[NOT (Carry flag)],并将结果保存到目标寄存器Rd中,并根据指令的执行结果设置CPSR中相应的标志位。
指令的语法格式:
RSC{<c>}{S} <Rd>,<Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标寄存器。
<Rn>:减数。
<shifter_operand>:被减数。
指令举例:
下面的程序使用RSC指令实现求64位数值的负数
rsbs r2,r0,#0 rsc r3,r1,#0
11.ADD指令
ADD指令将寄存器shifter_operand的值加上Rn表示的数值,并将结果保存到目标寄存器Rd中,并根据指令的执行结果设置CPSR中相应的标志位。
指令的语法格式:
ADD{<c>}{S} <Rd>,<Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标寄存器。
<Rn>:第一个操作数。
<shifter_operand>:要加的数。
指令举例:
add r0,r1,r2 ;r0=r1+r2 add r0,r1,#256 ;r0=r1+256 add r0,r2,r3,lsl#1 ;r0=r2+(r3<<1)
12.ADC指令
ADC指令将寄存器shifter_operand的值加上Rn表示的数值,再加上CPSR中的C条件标志位的值,将结果保存到目标寄存器Rd中,并根据指令的执行结果设置CPSR中相应的标志位。
指令的语法格式:
ADC{<c>}{S} <Rd>,<Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目标寄存器。
<Rn>:第一个操作数。
<shifter_operand>:要加的数。
指令举例:
ADC指令将两个操作数加起来,并把结果放置到目标寄存器中。它使用一个进位标志位,这样就可以做比32位大的加法。下面的例子将加两个128位的数
128位结果:寄存器R0,R1,R2和R3。
第一个128位数:寄存器R4,R5,R6和R7。
第二个128位数:寄存器R8,R9,R10和R11。
adds r0,r4,r8 adcs r1,r5,r9 adcs r2,r6,r10 adcs r3,r7,r11
13.CMP指令
CMP(Compare)指令使用寄存器Rn的值减去shifter_operand的值,根据操作的结果更新CPSR中相应的条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。
指令的语法格式:
CMP{<c>} <Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
<Rn>:第一个操作数。
<shifter_operand>:比较的数。
指令举例:
CMP指令允许把一个寄存器的内容与另一个寄存器的内容或立即值进行比较,更改状态来允许进行条件执行。它进行一次减法,但不存储结果,而是正确地更改标志位。标志位表示的是操作数1与操作数2比较的结果(其值可能为大于,小于,相等)。如果操作数1大于操作数2,则此后的有GT后缀的指令将可以执行。
显然,CMP不需要显式的指定S后缀来更改状态标志。
cmp r1,#10 beq loop
通过上面的例子可以看出,CMP指令与SUBS指令的区别在于CMP指令不保存运算结果,在进行两个数据大小判断时,常用CMP指令及其相应的条件码来进行操作。
14.CMN指令
CMN(Compare Negative)指令使用寄存器Rn的值减去shifter_operand的负数值,根据操作的结果更新CPSR中相应的条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。
指令的语法格式:
CMN{<c>} <Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
<Rn>:第一个操作数。
<shifter_operand>:比较的数。
指令举例:
CMN指令将寄存器Rn中的值加上shifter_operand表示的数值,根据加法的结果设置CPSR中相应的条件标志位。寄存器Rn中的值加上shifter_operand的操作结果对CPSR中条件标志位的影响。与寄存器Rn中的值减去shifter_operand的操作结果相反数对CPSR中条件标志位的影响有细微差别。
下面的指令使R0值加1,判断R0是否为1的补码,若是,则Z置位。
cmn r0,#1
15.TST测试指令
TST(Test)测试指令用于将一个寄存器的值和一个值进行比较。条件标志位根据两个操作数做“逻辑与”后的结果设置。
指令的语法格式:
TST{<c>} <Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
<Rn>:第一个操作数。
<shifter_operand>:比较的数。
指令举例:
下面的指令测试在R0中是否设置了位0。
tst r7,#0x4 addeq r6,r7 addne r8,r7
TST指令类似于CMP指令,不产生放置到目标寄存器中的结果。而是在给出两个操作数上进行操作并把结果反映到状态标志上。使用TST指令来检查是否设置了特定的位。操作数1是要测试的数据字而操作数2是一个位掩码。经过测试后,如果匹配则设置Z标志,否则清除它。与CMP指令一样,该指令不需要指定S后缀。
16.TEQ指令
TEQ(Test Equivalence)指令用于将一个寄存器的值和一个算术值做比较。条件标志位根据两个操作数做“逻辑异或”后的结果设置。以便后面的指令根据相应的条件标志来判断是否执行。
指令的语法格式:
TEQ{<c>} <Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
<Rn>:第一个操作数。
<shifter_operand>:比较的数。
指令举例:
teq r0,r1 ;r0与r1是否相等 addeq r0,r0,#1 ;若r0==r1,eq为真,则人r1=r1+1
二.乘法指令
1.MUL指令
MUL(Multiply)32位乘法指令将Rm和Rs中的值向乘,结果的最低32位保存到Rd中。
指令的语法格式:
MUL{<c>}{S} <Rd>,<Rn>,<shifter_operand>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目的寄存器。
<Rn>:第一个操作数。
<shifter_operand>:要与Rn相乘的数。
指令举例:
mul r1,r2,r3 ;r1=r2*r3 mul r0,r3,r7 :r0=r3*r7
2.MLA指令
MLA(Multiply Accumulate)32位乘一累加指令将Rm和Rs中的值相乘,再将乘积加上第3个操作数,结果的最低32位保存到Rd中。
指令的语法格式:
MLA{<c>}{S} <Rd>,<Rm>,<Rs>,<Rn>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rd>:目的寄存器。
<Rn>:第一个乘数。
<Rs>:第二个乘数。
<Rn>:与Rm和Rs的积相加。
指令举例:
下面的指令完成R1=R2*R3+10的操作
mla r1,r2,r3,#10
3.UMULL指令
UMULL(Unsigned Multiply Long)为64位无符号乘法指令,它将Rm和Rs中的值做无符号相乘,结果的低32位保存到RsLo中,高32为保存到RdHi中。
指令的语法格式:
UMULL{<c>}{S} <RdLo>,<RdHi>,<Rm>,<Rs>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rm>:第一个乘数。
<Rs>:第二个乘数。
<RdHi>:Rm与Rs的积的高32位。
<RdLo>:Rm与Rs的积的低32位。
指令举例:
umull r0,r1,r5,r8 ;(R1,R0)=R5*R8
4.UMLAL指令
UMLAL(Unsigned Multiply Accumulate Long)为64位无符号乘一累加指令,它将Rm和Rs中的值做无符号相乘,64位乘积与RdHi,RdLo相加,结果的低32位保存到RsLo中,高32为保存到RdHi中。
指令的语法格式:
UMLAL{<c>}{S} <RdLo>,<RdHi>,<Rm>,<Rs>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rm>:第一个乘数。
<Rs>:第二个乘数。
<RdHi>:Rm与Rs的积的高32位。
<RdLo>:Rm与Rs的积的低32位。
指令举例:
umlal r0,r1,r5,r8 ;(r1,r0)=r5*r8+(r1,r0)
5.SMULL指令
SMULL(Signed Multiply Long)为64位有符号长乘法指令,它将Rm和Rs中的值做有符号相乘,结果的低32位保存到RdLo中,高32为保存到RdHi中。
指令的语法格式:
SMULL{<c>}{S} <RdLo>,<RdHi>,<Rm>,<Rs>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rm>:第一个乘数。
<Rs>:第二个乘数。
<RdHi>:Rm与Rs的积的高32位。
<RdLo>:Rm与Rs的积的低32位。
指令举例:
smull r2,r3,r7,r6 ;(r3,r2)=r7*r6
6.SMLAL指令
SMLAL(Signed Multiply Accumulate Long)为64位有符号长乘一累加指令,它将Rm和Rs中的值做有符号相乘,64位乘积与RdHi,RdLo相加,结果的低32位保存到RdLo中,高32为保存到RdHi中。
指令的语法格式:
SMLAL{<c>}{S} <RdLo>,<RdHi>,<Rm>,<Rs>
{<c>}:为指令执行的条件码。当忽略时,指令为无条件执行。
{S}:决定指令的操作是否影响CPSR。
<Rm>:第一个乘数。
<Rs>:第二个乘数。
<RdHi>:Rm与Rs的积的高32位。
<RdLo>:Rm与Rs的积的低32位。
指令举例:
smlal r2,r3,r7,r6 ;(r3,r2)=r7*r6+(r3,r2)
三.访存指令
1.单寄存器Load/Store指令
1.1. LDR指令
LDR指令用于从内存中将一个32位的字读取到目标寄存器。
指令的语法格式:
LDR{<c>} <Rd>,<addr_mode>
指令举例:
ldr r1,[r0,#0x12] ;将r0+12地址处的数据读出,保存到r1中(r0的值不变) ldr r1,[r0] ;将r0地址处的数据读出,保存到r1中(零偏移) ldr r1,[r0,r2] ;将r0+r2地址处的数据读出,保存到r1中(r0的值不变) ldr r1,[r0,r2,lsl #2] ;将r0+r2*4地址的数据读出,保存到r1中(r0的值不变) ldr pc,[pc, #0x18] ;将程序跳转到pc+0x18位置处 ldr rd,label ;label为程序标号,label必须是当前指令的-4~4kb范围内 ldr rd,[rn],#0x04 ;rn的值用做传输数据的存储地址,在数据传送后,将偏移量0x04与rn相加,将结果写回到rn中,rn不允许是r15
1.2.STR指令
STR指令用于将一个32位的字数据写入到指令中指定的内存单元。
指令的语法格式:
STR{<c>} <Rd>,<addr_mode>
指令举例:
ldr r0, =0xE0200000 ldr r1, =0x00002222 str r1,[r0, #0x20]
1.3.LDRB指令
LDRB指令根据addr_mode所确定的地址模式将1个字节读取到指令中的目标寄存器Rd。
指令的语法格式:
LDRB{<c>} <Rd>,<addr_mode>
1.4.STRB指令
STRB指令从寄存器中取出指定的1个字节放入寄存器的低8位,并将寄存器的高位补0。
指令的语法格式:
STRB{<c>} <Rd>,<addr_mode>
1.5.LDRH指令
LDRH指令用于从内存中将一个16位的半字读取目标寄存器。
如果指令的内存地址不是半字对齐的,指令的执行结果不可预知。
指令的语法格式:
LDRH{<c>} <Rd>,<addr_mode>
1.6.STRH指令
STRH指令从寄存器中取出指定的16位半字放入寄存器的低16位,并将寄存器的高位补0。
指令的语法格式:
STRH{<c>} <Rd>,<addr_mode>
2.多寄存器Load/Store内存访问指令
2.1.LDM指令
LDM指令将数据从连续的内存单元中读取到指定的寄存器列表中的寄存器中。当PC包含在LDM指令的寄存器列表中,指令从内存中读取的字数据被当作目标地址值,指令执行后程序将目标地址处开始执行,从而实现了指令的跳转。
指令的语法格式:
LDM{<c>}<addressing_mode> <Rn>{!} <registers>
2.2.STM指令
STM指令将指令中寄存器列表中的各寄存器数值写入到连续的内存单元中。主要用于块数据的写入,数据栈操作及进入子程序时保存相关寄存器的操作。
指令的语法格式:
STM{<c>}<addressing_mode> <Rn>{!} <registers>
批量数据传送指令举例
LDM/STM批量加载/存储指令可以实现在一组寄存器和一块连续的内存单元之间传输数据。LDM为加载多个寄存器,STM为存储多个寄存器。允许一条指令传送16个寄存器的任何子集或所有寄存器。指令如下:
LDM{c}<模式> Rn{!},regist{^} STM{c}<模式> Rn{!},regist{^}
LDM/STM的主要用途有现场保护,数据复制和参数传递。其中模式有8种。
-
IA:每次传送后地址加4。
-
IB:每次传送前地址加4。
-
DA:每次传送后地址减4。
-
DB:每次传送前地址减4。
-
FD:满递减堆栈。
-
ED:空递增堆栈。
-
FA:满递增堆栈。
-
EA:空递增堆栈。
其中,寄存器Rn为基址寄存器,装有传送数据的地址,Rn不允许为R15:后缀“!”表示最后的地址写回Rn中;寄存器列表regist可包含多于一个寄存器或寄存器范围,使用“,”分开,如{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,LR} ;恢复现场,异常处理返回
使用LDM/STM进行数据复制
LDR R0,=SrcData ;设置源数据地址 LDR R1,=DstData ;设置目标地址 LDMIA R0,{R2~R9} ;加载8字数据到寄存器R2~R9 STMIA R1,{R2~R9} ;存储寄存器R2~R9到目标地址
使用LDM/STM进行现场寄存器保护,常在子程序或者处理使用。
SENDBYTE:STMFD SP!,{R0~R7,LR} ;寄存器压栈保护···BL DELAY···LDMFD SP!,{R0~R7,PC} ;恢复寄存器,并返回
3.单寄存器交换指令
3.1.SWP字交换指令
SWP指令用于将内存中的一个字单元和一个指定寄存器的值相交换。操作过程如下:假设内存单元地址存放在寄存器<Rn>中,指令将<Rn>中的数据督导目标寄存器Rd中,同时将另一个寄存器<Rm>的内容写入该内存单元中。
当<Rd>和<Rm>为同一个寄存器时,指令交换该寄存器和内存单元的内容。
指令的语法格式:
SWP{<c>} <Rd><Rm>[<Rn>]
3.2.SWPB字节交换指令
SWPB指令用于将内存中的一个字单元和一个指定寄存器的低8位值相交换。操作过程如下:假设内存单元地址存放在寄存器<Rn>中,指令将<Rn>中的数据督导目标寄存器Rd中,寄存器Rd的高24位设位0,同时将另一个寄存器<Rm>的低8位内容写入该内存单元中。
当<Rd>和<Rm>为同一个寄存器时,指令交换该寄存器低8位和内存单元的内容。
指令的语法格式:
SWP R1,R1,[R0] ;将R1的内容与R0指向的存储单元内容进行交换 SWPB R1,R2,[R0] ;将R0指向的存储单元内容读取一字节数据到R1中(高24位清零),并将R2的内容写入该内存单元中(最低字节有效),使用SWP指令可以方柏霓地进行信号量操作
四.跳转指令
1.跳转指令B及带连接的跳转指令BL
跳转指令B使程序跳转到指定的地址执行程序。带来连接的跳转指令BL将下一条指令的地址复制到R14(即返回地址连接寄存器中),然后跳转到指定地址运行程序。两条指令都可以根据CPSR中的条件标志位的值决定是否执行。
指令的语法格式:
B{L}{<c>} <targe_address>
BL指令用于实现子程序调用。子程序的返回可以通过将LR寄存器的值复制到PC寄存器来实现。下面3种指令可以实现子程序返回。
-
BX R14
-
MOV PC,R14
-
当子程序在入口处使用了压栈指令
STMFD R13!,{<registers>,R14}
可以使用指令:
LDMFD R13!,{<registers>,R14}
将子程序返回地址放入PC种
ARM汇编器通过以下步骤计算指令编码的signed_immed_24.
-
将PC寄存器的值作为本跳转指令的基地址值。
-
从跳转的目标地址种减去上面所说的跳转的基地址,生成字节偏移量。
-
当上面生成的字节偏移量超过-33554~+33554430时,不同的汇编器使用不同的代码产生策略。否则,将指令编码字中的signed_immed_24设置成上述字节偏移量的bits[25:2].
程序跳转到LABLE标号处。
b lable add r1,r2,#4 add r3,r2,#8 lable:sub r1,r2,#8
跳转到绝对地址
b 0x1234
跳转到子程序func处执行,同时将当前PC值保存到LR中
bl func
通过跳转指令建立一个无限循环。
loop:add r1,r2,#4add r3,r2,#8sub r3,r3,r1b loop
跳转使用跳转使程序体循环10次
mov r0,#10 loop:sub r0,#1bne loop
条件子程序调用示例。
cmp r0,#5 bllt sub1 blge sub2
2.带状态切换的跳转指令BX
带状态切换的跳转指令(BX)使用程序跳转到指令中指定的参数Rm指定的地址执行程序,Rm的第0位复制到CPSR中T位,bit[31:1]移入PC。若Rm的bit[0]为1,则跳转时自动将CPSR中的标志T置位,即把目标地址的代码解释位Thumb代码,反之,解释为ARM代码。
指令的语法格式:
BX{<c>} <Rm>
当Rm[1:0]=0b10时,指令的结果的执行结果不可预知。因为在ARM状态下,指令是4字节对齐的。
PC可以作为Rm寄存器使用。但这种用法不推荐使用。当PC作为<Rm>使用时,指令“BX PC”将程序跳转到当前指令下面第二条指令执行。虽然这样跳转可以实现,但最好使用下面的指令完成这样跳转。
MOV PC,PC 或 ADD PC,PC,#0
指令举例:
转移到R0中的地址,如果R0[0]=1,则进入Thumb状态
bx r0
3.带连接和状态切换的连接跳转指令BLX
带连接和状态切换的跳转指令(Branch with Link Exchange,BLX)使用标号,用以使程序跳转到Thumb状态或从Thumb状态返回。该指令为无条件执行指令,并用分支寄存器的最低位来更新CPSR中的T位,将返回地址写入连接寄存器LR中。
语法格式:
BLX <target_add>
其中,<target_add>为指令的跳转目标地址。该地址根据以下规则计算。
-
将指令中指定的24为偏移量进行符号扩展,形成32位立即数。
-
将结果左移两位
-
将H(bit[24])加到结果地址的第一位(bit[1])
-
将结果累加进程序计数器(PC)中。
计算偏移量的工作一般由ARM汇编器来完成。这种形式的跳转指令只能实现-32~32MB空间的跳转。左移两位形成偏移量,然后将其累加进程序计数器(PC)中。这时,程序计数器的内容为BX指令地址加8字节。位H(bit[24])加到结果地址的第一位(bit[1]),使目标地址成为半字地址,以执行接下来的Thumb指令。
指令举例:
从Thumb状态返回到ARM状态,使用BX指令
blx func
五.状态操作指令
1.MRS
MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。
在ARM处理器中,只有MRS指令可以将状态寄存器CPSR或SPSR读出到通用寄存器中。
指令的语法格式
MRS{<c>} Rd,PSR
其中Rd为目标寄存器,Rd不允许为程序计数器(PC)。PSR为CPSR或SPSR。
指令举例:
mrs r1,cpsr ;将cpsr状态寄存器读取,保存到r1中 mrs r2,spsr ;将spsr状态寄存器读取,保存到r1中
MRS指令读取CPSR,可用来判断ALU的状态标志及IRQ/FIQ中断是否允许等;在异常处理程序中,读SPSR可指定进入异常前的处理器模式切换,允许/禁止IRQ/FIQ中断等设置。另外,进程切换或者异常中断嵌套时,也可以使用MRS读取SPSR状态值并保存起来。
2.MSR
在ARM处理器中,只有MSR指令直接设置状态寄存器CPSR或SPSR。
指令的语法格式:
MSR{c} PSR_fields,#immod_8r MSR{c} PSR_fields,Rm
其中PSR是指CPSR或SPSR。<fields>设置状态寄存器中需要操作的位。状态寄存器的32位可以分为4个8位的域。bit[31:24]为条件标志位域,用f表示;bit[23:16]为状态标志位域,用s表示;bit[15:8]为扩展位域,用x表示;bit[7:0]为条件控制位域,用c表示;immod_8r要传送到状态寄存器指定域的立即数,8位;Rm为要传送到状态寄存器指定域的数据源寄存器。
指令举例:
msr cpsr,#0xd3 ;cpsr[7:0]=0xd3,切换到管理模式 msr cpsr,r3
注意:
只有在特权模式下才修改状态寄存器。
程序中不能通过MSR指令直接修改CPSR中的T位控制位来实现ARM状态/THumb状态的切换,必须使用BX指令来完成处理器状态的切换(因为BX指令属转移指令,它会打断流水线状态,实现处理器状态的切换)。MRS与MSR配合使用,实现CPSR或SPSR寄存器读-修改-写操作,可用来进行处理器模式切换及允许/禁止IRQ/FIQ中断等设置。
3.程序状态寄存器指令的应用
使能IRQ中断
enable_irq:mrs r0,cpsrbic r0,r0,#0x80msr cpsr_c,r0mov pc,lr
禁止IRQ中断
disable_irq:mrs r0,cpsrorr r0,r0,#0x80msr cpsr,r0mov pc,lr
设置中断模式堆栈:
msr cpsr,#0xd2 ldr sp,stacksvc
六.协处理器指令
1.ARM寄存器到协处理器寄存器的数据传送指令MCR
指令的语法格式
MCR<c> <coproc>,<opcl>,<Rt>,<CRn>,<CRm>{,<opc2>}
<c>:为指令执行的条件码。当忽略<c>时,指令为无条件执行
<coproc>:协处理器名称,范围p0~p15
<opcl>:协处理器操作码,范围0~15
<Rt>:源寄存器,将Rt寄存器写入协处理器
<CRn>:协处理器的目标寄存器
<CRm>:协处理器中附加的目标寄存器或者源操作寄存器,如果不需要附加信息就设置为C0,否则结果不可预测
<opc2>:可选的协处理器特定操作码,当不需要时置0.
2.协处理器寄存器到ARM寄存器的数据传送指令MRC
指令的语法格式
MRC<c> <coproc>,<opcl>,<Rt>,<CRn>,<CRm>{,<opc2>}
<c>:为指令执行的条件码。当忽略<c>时,指令为无条件执行
<coproc>:协处理器名称,范围p0~p15
<opcl>:协处理器操作码,范围0~15
<Rt>:源寄存器,将协处理器的内容读取到Rt寄存器
<CRn>:协处理器的目标寄存器
<CRm>:协处理器中附加的目标寄存器或者源操作寄存器,如果不需要附加信息就设置为C0,否则结果不可预测
<opc2>:可选的协处理器特定操作码,当不需要时置0.
指令举例
mrc p15,0,r1,c1,c0,0 orr r1,r1,#(1<<2) //set C bit 整体使能CaChe orr r1,r1,#(1<<12) //set I bit 整体使能ICaChe mcr p15,0,r1,c1,c0,0
七.异常产生指令
软件中断指令(SWI)用于产生软中断,从而实现从用户模式变换管理模式,CPSR保存到管理模式的SPSR中,执行执行转移到SWI向量,在其他模式下也可以使用SWI指令,处理器同样切换到管理模式。
指令的语法格式
SWI{<c>} <immod_24>