第三章 ARM指令集


一、ARM处理器寻址方式

1、寄存器寻址

  寄存器寻址的作数的值在寄存器中,指令中的地址码字段指出的是寄存器编号,指令执行时直接取出寄存器值来操作,例如:

  MOV  R1,R2	      ;表示将R2寄存器的值赋值给R1寄存器中

2、立即寻址

  立即寻址指令中的操作码字段后面的地址码部分即是操作数本身(这样的数称为立即数),也就是说,数据就包含在指令当中,例如:

  MOV	R0,#0xFF000   ;将立即数0xFF000装入R0寄存器中

3、寄存器移位寻址

  寄存器移位寻址是ARM指令集特有的寻址方式。当为这种寻址方式时,第2个寄存器中的操作数在与第1个寄存器的操作数结合之前,会先进行移位操作,例如:

  MOV	R1,R2,LSL #3   ;R2寄存器中的值左移3位,结果放入R1寄存器中

4、寄存器间接寻址

  寄存器间接寻址指令中的地址码给出的是一个通用寄存器的编号,所需的操作数保存在寄存器指定地址的存储单元中,即寄存器为操作数的地址指针,例如:

  LDR	R1,[R2]	       ;将R2寄存器中存储的地址所指向的存储单元的数据赋值到R1寄存器中

5、基址寻址

  基址寻址就是将基址寄存器的内容与指令中给出的偏移量相加,形成操作数的有效地址,例如:

  LDR	R1,[R2,#0x0C]  ;将R2寄存器中的值加上0x0C后,所得到的地址指向存储单元的内容,赋值给R1

6、多寄存器寻址

  多寄存器寻址一次可传送几个寄存器值,允许一条指令传送至多16个寄存器。寄存器的顺序是按由小到大的顺序排列,连续的寄存器可用“-”连接,否则用“ , ”分隔书写,例如:

  LDMIA	R1!,{R2-R7,R12}  ;将R1指向的单元中的数据读出到R2~R7、R12中(R1自动加4) 

7、堆栈寻址

  堆栈寻址是隐含的,它使用一个专门的寄存器(堆栈指针)指向一块存储区域(堆栈),指针所指向的存储单元即是堆栈的栈顶。其中堆栈分为四种类型:

  • 满递增:堆栈向高地址方向增长,堆栈指针指向有效数据项增长方向的最后一个数据。
  • 空递增:堆栈向高地址方向增长,堆栈指针指向有效数据项增长方向的最后一个数据的下一个位置。
  • 满递减:堆栈向低地址方向增长,堆栈指针指向有效数据项增长方向的最后一个数据。
  • 空递减:堆栈向低地址方向增长,堆栈指针指向有效数据项增长方向的最后一个数据的下一个位置。

  具体指令有LDM、STM指令等。

8、块拷贝寻址

  块拷贝寻址方式使用多寄存器传送指令将数据块从存储器的某一位置拷贝到另一位置。

  具体指令有LDM、STM指令等。

9、相对寻址

  相对寻址是基址寻址的一种变通。由程序计数器PC提供基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址即为操作数的有效地址。

      ...
    BL SUBRl   ;调用到SUBRl子程序
      ...
  SUBR;
      ...
    MOV PC,R14 ;返回

二、ARM指令集介绍

1、指令格式

  ARM指令的基本格式如下:

   <opcode> { <cond> } {S} <Rd> , <Rn> { , <operand2> }

  其中<>号内的项是必须的,{ }号内的项是可选的。各项的说明如下:

  • opcode:指令助记符;

  • cond:执行条件;

  • S:是否影响CPSR寄存器的值;

  • Rd:目标寄存器;

  • Rn:第1个操作数的寄存器;

  • operand2:第2个操作数;

    • 形式1:#immed_8r——常数表达式
    MOV    R0,#1              ;R0 ←1
    AND    R1,R2,#0x0F       ;R2与0x0F,结果保存在R1
    LDR    R0,[R1],#-4       ;先将R1指向内存中的数存入R0之后,
    		                   ;传送完成后 R1← R1-4,后变址
    
    • 形式2:Rm——寄存器方式
    SUB    R1,R1,R2          ; R1-R2→R1
    LDR    R0,[R1],-R2       ;先将R1指向内存中的数存入R0之后, 
                               ;  传送完成后R1 ← R1- R2,后变址
    
    • 形式3:Rm,shift——寄存器移位方式
      将寄存器的移位结果作为操作数,但Rm值保持不变,移位方法如下:
    操作码说明操作码说明
    ASR #n算术右移n位ROR #n循环右移n位
    LSL #n逻辑左移n位RRX带扩展的循环右移1位
    LSR #n逻辑右移n位
    ADD    R1,R1,R1,LSL #3    ;R1=R1+R1×8
    SUB    R1,R1,R2,LSR #2    ;R1=R1-R2÷4
    

2、条件码

操作码条件助记符标志含义
0000EQZ=1相等
0001NEZ=0不相等
0010CS/HSC=1无符号数大于或等于
0011CC/LOC=0无符号数小于
0100MIN=1负数
0101PLN=0正数或零
0110VSV=1溢出
0111VCV=0没有溢出
1000HIC=1,Z=0无符号数大于
1001LSC=0,Z=1无符号数小于或等于
1010GEN=V有符号数大于或等于
1011LTN!=V有符号数小于
1100GTZ=0,N=V有符号数大于
1101LEZ=1,N!=V有符号数小于或等于
1110AL任何无条件执行 (指令默认条件)
1111NV任何从不执行(不要使用)

3、ARM存储器访问指令

(1)单寄存器加载——LDR

助记符说明操作条件码位置
LDR Rd,addressing加载字数据Rd←[addressing],addressing索引LDR{cond}
LDRB Rd,addressing加载无符号字节数据Rd←[addressing],addressing索引LDR{cond}B
LDRT Rd,addressing以用户模式加载字数据Rd←[addressing],addressing索引LDR{cond}T
LDRBT Rd, addressing以用户模式加载无符号字节数据Rd←[addressing],addressing索引LDR{cond}BT
LDRH Rd, addressing加载无符号半字数据Rd←[addressing],addressing索引LDR{cond}H
LDRSB Rd, addressing加载有符号字节数据Rd←[addressing],addressing索引LDR{cond}SB
LDRSH Rd, addressing加载有符号半字数据Rd←[addressing],addressing索引LDR{cond}SH

注意事项:

  • LDRSB, LDRSH加载后高位需要填充符号位;
  • 有符号位加载是指用符号位加载扩展到32位,无符号半字加载是指用零扩展到32位;

(2)单寄存器存储——STR

助记符说明操作条件码位置
STR Rd, addressing存储字数据[addressing]←Rd, addressing索引STR{cond}
STRB Rd,addressing存储字节数据[addressing]←Rd, addressing索引STR{cond}B
STRT Rd,addressing以用户模式存储字数据[addressing]←Rd, addressing索引STR{cond}T
STRBT Rd,addressing以用户模式存储字节数据[addressing]←Rd, addressing索引STR{cond}BT
STRH Rd,addressing存储半字数据[addressing] ←Rd, addressing索引STR{cond}H

注意事项:

  • 半字读写的指定地址必须为偶数,否则将产生不可靠的结果;
  • 若指令有T,那么即使处理器是在特权模式下,存储系统也将访问看成是在用户模式下进行的;

(3)多寄存器存取——LDM和STM

  LDM和STM指令可以实现在一组寄存器和一块连续的内存单元之间传输数据。LDM为加载多个寄存器,STM为存储多个寄存器。指令格式如下:

  LDM/STM{cond}<模式> Rn{!},reglist{^}

  其中后缀“ ! ”表示最后的地址写回到Rn中,后缀“ ^ ”表示进行数据传送且寄存器列表不包含PC时,加载/存储的是用户模式的寄存器(在异常模式中默认操作对象为异常模式的寄存器)。

  <模式>表示地址变化规则,具体如下:

模式(数据块)说明模式(堆栈)说明
IA每次传送后地址加4FD满递减堆栈
IB每次传送前地址加4ED空递减堆栈
DA每次传送后地址减4FA满递增堆栈
DB每次传送前地址减4EA空递增堆栈

在这里插入图片描述

注意事项:

  • Rn此处没有[ ],但仍然指向内存;
  • 进行数据复制时,先设置好源数据指针和目标指针;
  • 进行堆栈操作操作时,要先设置堆栈指针(SP);
  • 存器Rn为基址寄存器,装有传送数据的初始地址,Rn不允许为R15;
  • 后缀“^”不允许在用户模式或系统模式下使用;
  • 若在LDM指令且寄存器列表中包含有PC时使用,那么除了正常的多寄存器传送外,将SPSR也拷贝到CPSR中,这可用于异常处理返回;

(4)寄存器和存储器交换指令

  SWP指令用于将一个内存单元(该单元地址放在寄存器Rn中)的内容读取到一个寄存器Rd中,同时将另一个寄存器Rm的内容写入到该内存单元中。指令格式如下:

  SWP{cond}{B} Rd,Rm,[Rn]

  其中,后缀“ B ”表示交换字节,若没有则表示交换32位字。Rd用于保存从存储器中读入的数据;Rm的数据用于存储到存储器中,若Rm与Rd相同,则为寄存器与存储器内容进行交换。Rn为要进行数据交换的存储器地址。

注意事项:

  • Rn不能与Rd和Rm相同

地址偏移类型:

  • 零偏移: 如:LDR Rd,[Rn]
  • 前索引偏移(前变址):如:LDR Rd,[Rn,#0x04]
  • 后索引偏移(后变址):如:LDR Rd,[Rn],#0x04

4、ARM数据处理指令

  数据处理指令只能对寄存器的内容进行操作,而不能对内存中的数据进行操作。

(1)数据传送指令

助记符说明操作条件码位置
MOV Rd,operand2数据传送Rd←operand2MOV{cond}{S}
MVN Rd,operand2数据取非后传送Rd←(~operand2)MVN{cond}{S}

(2)算术逻辑运算指令

  算数指令

助记符说明操作条件码位置
ADD Rd, Rn, operand2加法运算指令Rd←Rn+operand2ADD{cond}{S}
SUB Rd, Rn, operand2减法运算指令Rd←Rn-operand2SUB{cond}{S}
RSB Rd, Rn, operand2逆向减法指令Rd←operand2-RnRSB{cond}{S}
ADC Rd, Rn, operand2带进位加法Rd←Rn+operand2+CarryADC{cond}{S}
SBC Rd, Rn, operand2带进位减法指令Rd←Rn-operand2-(NOT)CarrySBC{cond}{S}
RSC Rd, Rn, operand2带进位逆向减法指令Rd←operand2-Rn-(NOT)CarryRSC{cond}{S}

  逻辑指令

助记符说明操作条件码位置
AND Rd, Rn, operand2逻辑与操作指令Rd←Rn & operand2AND{cond}{S}
ORR Rd, Rn, operand2逻辑或操作指令Rd←Rn | operand2ORR{cond}{S}
EOR Rd, Rn, operand2逻辑异或操作指令Rd←Rn ^ operand2EOR{cond}{S}
BIC Rd, Rn, operand2位清除指令(赋0)Rd←Rn & (~operand2)BIC{cond}{S}

(3)比较指令

  没有目的操作数,只用作更新条件标志位,不保存运算结果,指令后缀无需加S。

助记符说明操作条件码位置
CMP Rn, operand2比较指令标志N、Z、C、V ←Rn-operand2CMP{cond}
CMN Rn, operand2负数比较指令标志N、Z、C、V←Rn+operand2CMN{cond}
TST Rn, operand2位测试指令标志N、Z、C、V←Rn & operand2TST{cond}
TEQ Rn, operand2相等测试指令标志N、Z、C、V←Rn ^ operand2TEQ{cond}

5、乘法指令

助记符说明操作条件码位置
MUL Rd,Rm,Rs32位乘法指令Rd←Rm*Rs (Rd≠Rm)MUL{cond}{S}
MLA Rd,Rm,Rs,Rn32位乘加指令Rd←Rm*Rs+Rn (Rd≠Rm)MLA{cond}{S}
UMULL RdLo,RdHi,Rm,Rs64位无符号乘法指令(RdHi,RdLo) ←Rm*RsUMULL{cond}{S}
UMLAL RdLo,RdHi,Rm,Rs64位无符号乘加指令(RdHi,RdLo) ←Rm*Rs+(RdHi,RdLo)UMLAL{cond}{S}
SMULL RdLo,RdHi,Rm,Rs64位有符号乘法指令(RdHi,RdLo) ←Rm*RsSMULL{cond}{S}
SMLAL RdLo,RdHi,Rm,Rs64位有符号乘加指令(RdHi,RdLo) ←Rm*Rs+(RdHi,RdLo)SMLAL{cond}{S}

注意事项:

  • RdHi表示结果的高32位,RdLo表示低32位;

6、ARM分支指令

  分支指令跳转范围都为±32M字节,且ARM指令为字对齐,最低2位地址固定为0。

助记符说明操作条件码位置
B label分支指令PC←labelB{cond}
BL label带链接的分支指令LR←PC-4,PC←labelBL{cond}
BX Rm带状态切换的分支指令PC←label,切换处理器状态BX{cond}

注意事项:

  • BX指令,该指令可以根据跳转地址(Rm)的最低位来切换处理器状态,bit[0]=0为转为ARM状态,否则转为Thumb状态。

7、协处理器指令

助记符说明操作条件码位置
CDP coproc,opcode1,CRd,CRn, CRm{,opcode2}协处理器数据操作指令取决于协处理器CDP{cond}
LDC{L} coproc, CRd,<地址>协处理器数据读取指令取决于协处理器LDC{cond}{L}
STC{L} coproc, CRd,<地址>协处理器数据写入指令取决于协处理器STC{cond}{L}
MCR coproc,opcode1,Rd,CRn, CRm{,opcode2}ARM寄存器到协处理器寄存器的数据传送指令取决于协处理器MCR{cond}
MRC coproc,opcode1,Rd,CRn, CRm{,opcode2}协处理器寄存器到ARM寄存器到的数据传送指令取决于协处理器MRC{cond}

8、杂项指令

助记符说明操作条件码位置
SWI immed_24软中断指令产生软中断,处理器进入管理模式SWI{cond}
MRS Rd,psr读状态寄存器指令Rd←psrMRS{cond}
MSR psr_fields, Rd / #immed_8r写状态寄存器指令psr_fields←Rd / #immed_8rMSR{cond}

  SWI指令用于产生软中断,从而实现从用户模式变换到管理模式,并且将CPSR保存到管理模式的SPSR中,然后程序跳转到SWI异常入口。在其它模式下也可使用SWI指令,处理器同样地切换到管理模式。

  在ARM处理器中,只有MRS指令可以对状态寄存器CPSR和SPSR进行读操作。通过读CPSR可以了解当前处理器的工作状态。读SPSR寄存器可以了解到进入异常前的处理器状态。该指令不影响条件码。

  在ARM处理器中,只有MSR指令可以对状态寄存器CPSR和SPSR进行写操作。与MRS配合使用,可以实现对CPSR或SPSR寄存器的读-修改-写操作,可以切换处理器模式、或者允许/禁止IRQ/FIQ中断等。

注意事项:

  • psr为 CPSR或SPSR;
  • Rd不允许为R15;
  • 只有在特权模式下才能修改状态寄存器;
  • 程序中不能通过MSR指令直接修改CPSR中的T控制位来实现ARM状态/Thumb状态的切换,必须使用BX指令完成处理器状态的切换(因为BX指令属分支指令,它会打断流水线状态,实现处理器状态切换)。

9、ARM伪指令

  ARM伪指令不属于ARM指令集中的指令,是为了编程方便而定义的。伪指令可以像其它ARM指令一样使用,但在编译时这些指令将被等效的一条或多条ARM指令所代替。

(1)ADR伪指令——小范围的地址读取

  ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中,其指令格式如下:

  ADR{cond}  register , expr

  其中地址表达式expr的取指范围为-255~255B(字节对齐),或者-1024~1024B(字对齐)。
  示例:

    ... 
    ADR     R0,Delay    
    ...
Delay
    MOV     R0,r14
    ...

注意事项:

  • 通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。

(2)ADRL伪指令——中等范围的地址读取

  比ADR伪指令可以读取更大范围的地址,其指令格式如下:

  ADRL{cond}  register , expr

  其中地址表达式expr的取指范围为-64K~64KB(字节对齐),或者-256K~256KB(字对齐)。

注意事项:

  • 通常,编译器用两条合适的指令来实现该ADRL伪指令的功能。若不能用两条指令实现,则产生错误,编译失败。

(3)LDR伪指令——大范围的地址读取

  LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器。若加载的常数未超出MOV或MVN的范围,则使用MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量,其指令格式如下:

  LDR{cond}   register , = expr | label_expr

  示例:

  LDR R2, =0xFF0             ;MOV R2, #0xFF0
  LDR R0, =0xFF000000        ;MOV R0, #0xFF000000
  LDR R1, =0xFFFFFFFE        ;MVN R1, #0x1

注意事项:

  • 从指令位置到文字池的偏移量必须小于4KB;
  • 与ARM指令的LDR相比,伪指令的LDR的参数有“=”号;
  • 文字池其实就是一个存储常量数据的地方,汇编器会使用文字池来在代码段中存储常量数据;

(4)NOP伪指令——空操作

  NOP伪指令在汇编时将会被代替成ARM中的空操作,比如可能是“MOV R0,R0”指令等,主要用于延时操作,其指令格式如下:

  NOP


  • 39
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值