ARMv7体系结构汇总

2023-11-05

文章目录

1 .处理器工作模式

ARM微处理器支持7种工作模式,分别为:

  • 用户模式(usr):ARM处理器正常的程序执行状态
  • 快速中断模式(fiq):用于高速数据传输或通道处理
  • 外部中断模式(irq):用于通用的中断处理
  • 管理模式(svc):操作系统使用的保护模式
  • 中止模式(abt):当数据或指令预取终止时进入该模式,用于虚拟存储及存储保护。
  • 未定义指令模式(und):当未定义的指令执行时进入该模式,用于支持硬件协处理器的软件仿真。
  • 系统模式(sys):运行具有特权的操作系统任务。

2. 处理器工作状态

自从ARM7TDMI核产生后,体系结构中具有T变种的ARM处理器核可工作在两种状态,并可在两种状态之间切换:

  • ARM状态: ARM微处理器执行32位的ARM指令集。

  • Thumb状态:ARM微处理器执行16位的Thumb指令集

    处理器开始执行时候处于ARM状态。

3. ARM寄存器

3.1 通用寄存器

  • 未分组寄存器

    未分组寄存器包括R0~R7,在所有工作模式下,未分组寄存器都指向同一个物理寄存器,他们未被系统用作特殊的用途,因此,在中断或异常处理进行工作模式转换时,由于不同的处理器工作模式均使用相同的物理寄存器,可能会造成寄存器中数据的破坏,这一点在进行程序设计时应引起注意

  • 分组寄存器

    分组寄存器包括R8~R14,对于分组寄存器,他们每一次所访问的物理寄存器与处理器当前的工作模式有关。如图所示。对于R8~R12来说,每个寄存器对应两个不同的物理寄存器,当使用fiq模式时,访问寄存器R8_fiq~R12_fiq;当使用除fiq模式以外的其它模式时,访问寄存器R8_usr~R12_usr。

在这里插入图片描述

3.2 状态寄存器

ARM体系结构包含一个当前程序状态寄存器CPSR (R16)和五个备份的程序状态寄存器(SPSRs)。CPSR可在任何工作模式下被访问,用来保存ALU中的当前操作信息、控制允许和禁止中断、设置处理器的工作模式等。备份的程序状态寄存器用来进行异常处理。程序状态寄存器的基本格式如图所示:

在这里插入图片描述

  • 条件码标志

在这里插入图片描述

  • 控制位

    1. 中断禁止位
      中断禁止位包括I、F,用来禁止或允许IRQ和FIQ两类中断,当I=1时,表示禁止IRQ中断,I=0时,表示允许IRQ中断;当F=1时,表示禁止FIQ中断,F=0时,表示允许FIQ中断。
    2. T标志位
      T标志位用来标识/设置处理器的工作状态。对于ARM体系结构v4及以上的版本的T系列处理器,当该位为1时,程序运行于Thumb状态;当该位为0时,表示运行于ARM状态。ARM指令集和Thumb指令集均有切换处理器状态的指令。这些指令通过修改T位的值为1或0来实现在两种工作状态之间切换,但ARM微处理器在开始执行代码时,应该处于ARM状态。
    3. 工作模式位
      工作模式位(M[4:0])用来标识或设置处理器的工作模式。M4 、M3 、M2、M1、M0决定了处理器的工作模式。在这里插入图片描述
  • 保留位

    CPSR中的其余位为保留位,当改变CPSR中的条件码标志位或者控制位时,保留位不要被改变,在程序中也不要使用保留位来存储数据。保留位将用于ARM版本的扩展。

3.3 备份的程序状态寄存器SPSR

每一种工作模式下又都有一个专用的物理状态寄存器,称为SPSR(Saved Program Status Register,),当异常发生时,SPSR用于保存CPSR的当前值,从异常退出时则可由SPSR来恢复CPSR。由于用户模式和系统模式不属于异常模式,他们没有SPSR,当在这两种模式下访问SPSR,结果是未知的。CPSR和SPSR通过特殊指令进行访问。

【示例】假设某一刻,寄存器CPSR的值如图2-11所示,试说明处理器的条件标志、中断允许情况、工作状态以及工作模式。

在这里插入图片描述

分析:CPSR的bit[31~27]表示条件标志NZCVQ,其值分别为00100,为了便于阅读常常用字母表示其值,如图中所示:某一位为0则用小写字母表示,某一位为1,则用大写字母表示,则上述条件标志可表示为:nzCvq,即C标志位置位为1,其它标志位为0。因为bit[7~6]为iF,所以IRQ中断被使能,即允许CPU响应IRQ中断,FIQ中断被禁止。因为bit[5]为t,所以处理器工作在ARM状态。因为Bit[4~0]为10011,可知系统工作于管理模式(SVC) 。

3.4 Thumb寄存器

Thumb状态下的寄存器集是ARM状态下寄存器集的一个子集,程序可以直接访问8个通用寄存器(R7~R0)、程序计数器(PC)、堆栈指针(SP)、连接寄存器(LR)和CPSR。同时,在每一种特权模式下都有一组SP、LR和SPSR。

在这里插入图片描述

Thumb状态下的寄存器组织与ARM状态下的寄存器组织的关系:

  • Thumb状态下和ARM状态下的R0~R7是相同的。
  • Thumb状态下和ARM状态下的CPSR和所有的SPSR是相同的。
  • Thumb状态下的SP对应于ARM状态下的R13。
  • Thumb状态下的LR对应于ARM状态下的R14。
  • Thumb状态下的程序计数器对应于ARM状态下R15

在这里插入图片描述

4. ARM指令系统

4.1 指令和指令格式

  1. 指令和指令系统
    指令是指示计算机进行某种操作的命令
    指令的集合称为指令系统。指令系统的功能强弱在很大程度上决定了这类计算机智能
    的高低,它集中地反映了微处理器的硬件功能和属性。
  2. 指令的表示方法
    从形式上看,ARM指令在机器中的表示格式是用32位的二进制数表示。计算机根据二
    进制代码去完成所需的操作,如ARM中有一条指令为:
    ADDEQS R0,R1,#8;
    其二进制代码形式为:
    在这里插入图片描述

ARM指令代码一般可以分为5个域:

  • 第1个域是4位[31:28]的条件码域,4位条件码共有16种组合;

  • 第2个域是指令代码域[27:20],除了指令编码外,还包含几个很重要的指令特征和可选后缀的编码;

  • 第3个域是地址基址Rn,是4位[19:16],为R0~R15共16个寄存器编码;

  • 第4个域是目标或源寄存器Rd,是4位[15:12],为R0~R15共16个寄存器编码;第5个域是地址偏移或操作寄存器、操作数区[11:0]。

  1. 汇编指令格式
    用助记符表示的ARM指令一般格式如下:

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

    ​ 格式中<>的内容必不可少,{}中的内容可省略。如是指令
    ​ 助记符,是必须的。而{}为指令的执行条件,是可选的,缺省
    ​ 的情况下表示使用默认条件AL(无条件执行)。

    • 表示操作码,如ADD表示算术加法。

    • {}表示指令执行的条件域,如EQ、NE等。

    • {S}决定指令的执行结果是否影响CPSR的值,使用该后缀则指令执行的结果影响CPSR的值,否则不影响。

    • 表示目的寄存器。

    • 表示第一个操作数,为寄存器。

    • 表示第二个操作数,可以是立即数、寄存器和寄存器移位操作数。

      ​ 例如上述指令ADDEQS R0,R1,#8;其中操作码为ADD,条件域cond为EQ,
      ​ S表示该指令的执行影响CPSR寄存器的值,目的寄存器Rd为R0,第一个操
      ​ 作数寄存器Rn为R1,第二个操作数OP2为立即数#8。

      指令格式举例:

           LDR R0,[R1] ;读取R1地址上的存储单元的数据到寄存器R0
           BEQ ENDDATA  ;条件分支执行指令,执行条件EQ,即相等则跳转到ENDDATA处
           ADDS R2,R1,#1 ;寄存器R1中的内容加1存入寄存器R2,并影响CPSR寄存器的值
      

4.2 指令的可选后缀

S后缀

指令中使用S后缀时,指令执行后程序状态寄存器的条件标志位将被刷新,不使用S后缀时,指令执行后程序状态寄存器的条件标志将不会发生变化。 S后缀通常用于对条件进行测试,例如是否有溢出,是否进位等;根据这些变化,就可以进行一些判断,如是否大于,是否相等;从而可能影响指令执行的顺序。

示例 假设R0=0x1,R3=0x3,指令执行之前 CPSR=nzcvqIFt_SVC,分别执行如下指令CPSR的值有何变化?

 SUB R1,R0,R3    ;R0的值减去R3的值,结果存入R1
 SUBS R1,R0,R3   ;R0的值减去R3的值,结果存入R1,影响标志位

执行第1条指令对于标志寄存器的值没有任何影响,因此CPSR的值不变。执行第2条指令后CPSR=NzcvqIFt_SVC,因为R0的值减去R3值,结果变成了一个负数,故而N被置位了。

!后缀

如果指令地址表达式中不含!后缀,则基址寄存器中的地址值不会发生变化。指令中的地址表达式中含有!后缀时,指令执行后,基址寄存器中的地址值将发生变化,变化的结果如下:

基址寄存器中的值(指令执行后)=指令执行前的值+地址偏移量

示例 分别执行下面两条指令有何区别?

LDR R3,[R0,#4] 
LDR R3,[R0,#4]!

分析:在上述指令中,第1条指令没有后缀!,指令的结果是把R0加4作为地址指针,把这个指针所指向的地址单元所存储的数据读入R3,R0的值不变。第2条指令除了实现以上操作外,还把R0+4的结果送到R0中。

  • 使用!后缀需要注意如下事项:
    1. !后缀必须紧跟在地址表达式后面,而地址表达式要有明确的地址偏移量。
    2. !后缀不能用于R15(PC)的后面。
    3. 当用在单个地址寄存器后面时,必须确信这个寄存器有隐性的偏移量,例如“STMDB R1!{R3,R5,R7}”此时地址基址寄存器R1的隐性偏移量是4。

4.3指令的条件执行

程序要执行的指令,均保存在存储器中,当计算机需要执行一条指令时,首先产生这条指令的地址,并根据地址号打开相应的存储单元,取出指令代码,CPU根据指令代码的要求以及指令中的操作数,去执行相应的操作。
指令的条件码

示例 下面三条指令有何区别?

ADD R4,R3,#1
ADDEQ R4,R3,#1
ADDS R4,R3,#1

分析:第1条指令不带条件标志(无条件AL),指令的执行不受条件标志位的影响,完成加法运算:将R3的值加1存入寄存器R4。第2条 ADD指令加上后缀EQ变为ADDEQ表示“相等则相加”,即当CPSR中的Z标志置位时该指令执行,否则不执行。第3条指令的执行也不受条件标志的影响,但是由于附带了后缀S,这条指令执行的结果将影响CPSR中条件标志位的值。

条件后缀只是影响指令是否执行,不影响指令的内容,如上述ADDEQ指令,可选后缀EQ并不影响本指令的内容,它执行时仍然是一条加法指令。

条件后缀和S后缀的关系如下:

  • 如果既有条件后缀又有S后缀,则书写时S排在后面,如:ADDEQS R1,R0,R2
  • 该指令在Z=1时执行,将R0+R2的值放入R1,同时刷新条件标志位。
  • 条件后缀是要测试条件标志位,而S后缀是要刷新条件标志位。
  • 条件后缀要测试的是执行前的标志位,而S后缀是依据指令的结果改变条件标志。

4.4 ARM指令分类

ARM微处理器的指令集是加载/存储型的,即指令集中的大部分指令仅能处理寄存器中的数据,而且处理结果都要放回寄存器,而对系统存储器的访问则需要通过专门的加载/存储指令来完成。

ARM微处理器的指令集可以分为六大类:

  • 数据处理指令

  • 数据加载与存储指令

  • 分支指令

  • 程序状态寄存器(PSR)处理指令

  • 协处理器指令

  • 异常产生指令

5 . ARM指令的寻址方式

5.1 立即数寻址

立即数寻址也叫立即寻址,操作数本身就在指令中给出,取出指令也就取到了操作数。这个操作数被称为立即数,对应的寻址方式也就叫做立即寻址。

例 MOV R0,#15

在这里插入图片描述

立即数要求以“#”为前缀,对于以十六进制表示的立即数,还要求在“#”后加上“0x”或“&”;对于以二进制表示的立即数,要求在“#”后加上“0b”; 对于以十进制表示的立即数,要求在“#”后加上“0d”或缺省。此指令是将立即数15传送到R0中,该指令的机器编码为E3A0000FH,由指令编码中0x00F即可得到一个32位的立即0x0000000FH,这个数再送入R0。

5.2 寄存器寻址

寄存器寻址就是利用寄存器中的数值作为操作数,这种寻址方式是各类微处理器经常采用的一种方式,也是一种执行效率较高的寻址方式。

例 ADD R0,R1,R2 ;R0←R1+R2

在这里插入图片描述

5.3 寄存器间接寻址

寄存器间接寻址就是以寄存器中的值作为操作数的地址,而操作数本身存放在存储器中。

例 LDR R0,[R4] ;R0←[R4]

在这里插入图片描述

5.4 寄存器移位寻址

寄存器移位寻址的操作数由寄存器中的数值做相应移位而得到。

ADD R0,R1,R2,LSL #1

MOV R0,R1,LSL R3

在这里插入图片描述

5.5 基址变址寻址

基址变址寻址就是将寄存器(该寄存器一般称作基址寄存器)的内容与指令中给出的地址偏移量相加,从而得到一个操作数的有效地址。

LDR R0,[R1,#4]    ;R0←[R1+4]
LDR R0,[R1,#4]! ;R0←[R1+4]、R1←R1+4
LDR R0,[R1],#4   ;R0←[R1]、R1←R1+4
LDR R0,[R1,R2]    ;R0←[R1+R2]

在这里插入图片描述

5.6 多寄存器寻址

采用多寄存器寻址方式,一条指令可以完成多个寄存器值的传送。这种寻址 方式中用一条指令最多可传送16个通用寄存器的值。连续的寄存器间用“-”连接,否则用“,”分隔。

LDMIA R0!,{R1-R4}  ;R1←[R0]
                    ;R2←[R0+4]		
                    ;R3←[R0+8]

指令执行前内存和寄存器值

在这里插入图片描述

指令执行后内存和寄存器值

在这里插入图片描述

5.7 相对寻址

与基址变址寻址方式相类似,相对寻址以程序计数器PC的当前值为 基地址,指令中的地址标号作为偏移量,将两者相加之后得到操作数 的有效地址。

以下程序段完成子程序的调用,分支指令BL采用了相对寻址方式:

         BL proc  ;跳转到子程序proc处执行
                   …		
          proc  MOV R0,#1
                   …	 

5.8 堆栈寻址

堆栈是一种数据结构,按后进先出(Last In First Out, LIFO)的方式工作, 使用一个称作堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶。

ARM中采用LDMFD和STMFD指令分别用来支持POP操作(出栈)和PUSH操作(进栈),R13作为堆栈指针。

STMFD R13!,{R0-R4};
LDMFD R13!,{R0-R4};

6. 数据处理指令

数据处理指令对存放在寄存器中的数据进行操作,分为:

  • 数据传送指令
  • 移位操作
  • 算术指令
  • 逻辑运算指令
  • 比较指令
  • 乘法指令

算术逻辑运算指令完成常用的算术与逻辑运算,这两类指令不但将运算结果保存在目的寄存器中,同时更新CPSR中的相应条件标志位。比较指令不保存运算结果,只更新CPSR中相应的条件标志位。

在这里插入图片描述

  • cond: 指令执行的条件码
  • I :用于区别第二操作数是立即数(I=1)还是寄存器移位(I=0)
  • opcode: 数据处理指令操作码
  • S : 用于设置条件码,S=0,条件码不改变, S=1,条件码根据具体指令的结果修改
  • Rn : 第一操作数寄存器
  • Rd :目标寄存器
  • Operand2 :第二操作数,该数可以是立即数或寄存器移位数。

6.1 数据传送指令

数据传送指令主要用于将一个寄存器中的数据传送到另一个寄存器,或者将一个立即数传送到寄存器,这类指令通常用来设置寄存器的初始值。

数据传送指令包括:

  • MOV数据传送指令

  • MVN数据取反传送指令

MOV指令

汇编格式:MOV {} {S} Rd,operand2

功 能:MOV指令将源操作数operand2传送到目的寄存器Rd中。通常 operand2是一个立即数、寄存器Rm或被移位的寄存器。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令 执行后的结果影响CPSR中条件标志位N和Z值,在计算第2操作数时更新标志C,不影响V标志。

例 3.12 MOV指令示例:

 MOV  R1,R0           ;将寄存器R0的值传送到寄存器R1
 MOV  PC,R14          ;将寄存器R14的值传送到PC,常用于子程序返回
 MOV  R1,R0,LSL#3   ;将寄存器R0的值左移3位后传送到R1  
 MOV  R0,#5           ;将立即数5传送到寄存器R0
MVN指令

汇编格式:MVN{}{S} Rd,operand2

功 能:MVN指令可完成从另一个寄存器、被移位的寄存器或将一个立即数传送到目的寄存器Rd。与MOV指令不同之处是:数据在传送之前被按位取反了,即把一个被取反的值传送到目的寄存器中。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志位N和Z值,在计算第2操作数时更新标志C,不影响V标志。

​ 例 3.13 MVN指令示例:

     MVN R0,#0 ;将立即数0取反传送到寄存器R0中,完成后R0=-1
     MVN R1,R2  ;将R2取反,结果存到R1中

6.2 移位操作

ARM微处理器一个显著的特征是:在操作数进入ALU之前,对操作数进行预处理。如:指定位数的左移或右移,这种功能明显增强了数据处理操作的灵活性。这种预处理是通过ARM微处理器内嵌的桶形移位器(Barrel Shifter)来实现的。

桶形移位器和ALU的关系如图所示

在这里插入图片描述

桶形移位器支持数据的各种移位操作,移位操作在ARM指令集中不作为单独的指令 使用,它只能作为指令格式中的一个字段, 在汇编语言中作为指令中的选项。例如,数据处理指令的第二个操作数为寄存器时,就可以加入移位操作选项对它进行各种移位操作。

移位操作包括如下5种类型:

  • LSL 逻辑左移
  • LSR 逻辑右移
  • ASR 算术右移
  • ROR 循环右移
  • RRX 带扩展的循环右移
1.LSL逻辑左移

汇编格式:Rm,LSL

在这里插入图片描述

功 能:LSL指令可完成对通用寄存器Rm中的内容进行逻辑左移操作,按操作数op1所指定的数量向左移位,低位用零来填充。逻辑左移一次相当于将无符号数据做乘2操作。逻辑左移如图3-12所示。指令格式中的操作数op1 用来控制左移的次数,op1有如下两种表示方式:

  • 立即数控制方式
    立即数控制方式就是寄存器Rm移位的位数由一个数值常量来控制,例如:

    Rm,LSL #2
    

    在这个表达式中,对Rm中的数据逻辑左移2位。使用立即数控制方式时必须满足:
    0≤立即数≤31。

    在这个表达式中,对Rm中的数据逻辑左移2位。使用立即数控制方式时必须满足:
    0≤立即数≤31。

  • 寄存器控制方式
    寄存器控制方式就是寄存器Rm移位的位数由另一个寄存器Rs来控制,Rs是通用寄存器,但不可使用R15(程序计数器)。例如:

    Rm,LSL Rs
    

    假设Rs的值为3,则在这个表达式中表示对Rm中的数据逻辑左移3位。同样使用寄存器控制方式也必须满足:0≤Rs≤31。

例1 设指令操作之前R0=0x00000000,R1=0x80000004,则执行如下指令后R0,R1的值有何变化?

MOV  R0, R1, LSL#1

例 2 设指令操作之前CPSR=nzcvqiFt_USER,R0=0x00000000,R1=0x80000004,则执行如下指令后R0,R1,CPSR中的值有何变化?

MOVS  R0, R1, LSL#1

在这里插入图片描述

2.LSR逻辑右移

汇编格式:Rm,LSR

功 能:LSR指令可完成对通用寄存器Rm中的数据,按操作数op1所指定的数量向右移位,空出的最高位用零来填充。逻辑右移一次相当于将无符号数据做除2 操作。逻辑右移如图所示

在这里插入图片描述

指令格式中的操作数op1用来控制右移的次数,关于操作数op1的要求如LSL指令所述,唯一区别是取值范围要求:1≤立即数或Rs≤32。同样地,当指令中附加了S选项时,移位指令操作的结果还将影响CPSR中的标志位。

例 设指令操作之前CPSR=nzcvqiFt_USER,R0=0xFFFFFFFF,R1=0x00000001,则执行如下指令后R0,R1,CPSR中的值有何变化?

MOVS  R0, R1, LSR#1
3.ASR算术右移

汇编格式:Rm,ASR

功 能:ASR可完成对通用寄存器中的内容,按操作数所指定的数量向右移位,左端用第31位的值来填充。算术右移如图所示。

在这里插入图片描述

指令格式中的操作数op1用来控制右移的次数,关于操作数op1的要求如LSL指令所述,唯一区别是取值范围要求:1≤立即数或Rs≤32。同样地,当指令中附加了S选项时,移位指令操作的结果还将影响CPSR中的标志位。

例 设指令操作之前CPSR=nzcvqiFt_USER,R0=0x00000000,R1=0x80000001,则执行如下指令后R0,R1,CPSR中的值有何变化?

 MOVS  R0, R1, ASR#1
4.ROR循环右移

汇编格式:Rm,ROR

功 能:ROR可完成对通用寄存器中的内容,按操作数所指定的数量向右循环移位,左端用右端移出的位来填充。循环右移如图所示。

在这里插入图片描述

指令格式中的操作数op1用来控制右移的次数,关于操作数op1的要求如LSL指令所述,取值范围要求:1≤立即数或Rs≤31。同样地,当指令中附加了S选项时,移位指令操作的结果还将影响CPSR中的标志位。

例 设指令操作之前R0=0x00000000,R1=0x40000001,则执行如下指令后R0,R1的值有何变化?

MOV  R0, R1, ROR #1
5.RRX带扩展的循环右移

汇编格式:Rm,RRX

功 能:RRX可完成对通用寄存器中的内容进行带扩展的循环右移一位的操 作,右移时32位数据和C标志位共33位数据组成一个循环往右移一次。 C标志位移入最高位,最低位移入C位。带扩展的循环右移如图所示。

在这里插入图片描述

例 设指令操作之前CPSR=nzcvqiFt_USER,R0=0x00000000,R1=0x80000001,则执行如下指令后R0,R1,CPSR中的值有何变化 ?

 MOVS  R0, R1, RRX

6.3 算术指令

ARM中的算术指令主要指加法和减法,这些指令主要实现两个32位数据的加 减操作,该类指令常常和桶形移位器结合起来,获得许多灵活的功能。算术指令主要包括:

  • ADD 加法指令

  • ADC 带进位加法指令

  • SUB 减法指令

  • SBC 带借位减法指令

  • RSB 逆向减法指令

  • RSC 带借位的逆向减法指令

1. ADD 加法指令

汇编格式:ADD{}{S} Rd,Rn,operand2

功 能:ADD指令用于把寄存器Rn的值和操作数operand2相加,并将结果存放到Rd寄存器中。即Rd=Rn+ operand2,其中Rd为目的寄存器,Rn为操作数1,要求是一个寄存器,operand2是操作数2,可以是一个寄 存器,被移位的寄存器,或一个立即数。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志位N、Z、C、V标志。

例 ADD指令示例:

 ADD R0,R1,R2         ; R0 = R1 + R2
 ADD R0,R1,#5         ; R0 = R1 + 5
 ADD R0,R1,R2,LSL#2   ; R0 = R1 + (R2左移2位)
  • 立即数控制的寄存器移位表达式

立即数控制方式就是寄存器Rm移位的位数由一个数值常量来控制,例如:

   ADD R0,R1,R2,LSL#2  ; R0 = R1 + (R2左移2位)

在这个表达式中,对R2中的数据逻辑左移2位, 然后和R1相加,其结果放入寄存器R0中。

  • 寄存器控制的寄存器移位方式
    寄存器控制方式就是寄存器Rm移位的位数由另一个寄存器Rs来控制,Rs是通用寄存器,但不可使用R15(程序计数器)。例如:
  ADD R0,R1,R2,LSL R3

假设R3的值为3,则在这个表达式中表示对R2中的数据逻辑左移3位,然后和R1相加,其结果放入寄存器R0中。

  • 数字常量表达式

数字常量表达式可以简单到一个立即数,还可以使用单目操作符、双目操 作符、逻辑操作符和算术操作符等。例如:

#0x88               ;立即数
#0x40+0x20          ;使用加法
#0x40+0x20*4         ;使用加减乘除算术运算
#0x80:ROR:02         ;使用移位操作,循环右移2位
#2_11010010          ;使用二进制
#0xFF:MOD:08         ;取模操作
#0xFF0000:AND:660000 ;逻辑操作,两数相与
2. ADC带进位加法指令

汇编格式:ADC{}{S} Rd,Rn, operand2

功能:ADC指令用于把寄存器Rn的值和操作数operand2相加,再 加上CPSR中的C条件标志位的值,并将结果存放到目的寄存器Rd中。即Rd=Rn+ operand2+C, 其中Rn为操作数1,必须是一个寄存器,operand2为操作数2,可以是一个寄存器,被移位的寄存器,或一个立即数。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志位N、Z、C、V标志。该指令使用一个进位标志位,这样就可以做比32位大的数的加法,注意不要忘记设置S后缀来更改进位标志。该指令用于实现超过32位的加法。

例 用ADC指令完成64位加法,设第一个64位操作数放在R2、R3中,第二个64位操作数放在R4、R5中。64位结果放在R0、R1中。

分析:首先将两个64位数中的低32位相加,相加结果影响C标志位。然后将64位中的高32位以及低32位产生的进位相加。程序如下:

ADDS R0,R2,R4 	;加第32位,S表示影响条件标志位的值
ADC R1,R3,R5	;加高32位,带进位
3. SUB减法指令

汇编格式:SUB{}{S} Rd,Rn,operand2

功能:SUB指令用于把寄存器Rn的值减去操作数operand2,并将结果存放到目的寄存器Rd中。即Rd=Rn- operand2, 其中Rd为目的寄存器,Rn为操作数1,必须是一个寄存器,operand2是操作数2,可以是一个寄存器,被移位的寄存器或一个立即数。该指令可用于有符号数或无符号数的减法运算。S选项决定指令操作的结果是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志位N、Z、C、V标志。

SUB指令示例:

SUB R0,R1,R2        	;R0 = R1 - R2
SUB R0,R1,#6        	;R0 = R1 - 6
SUB R0,R2,R3,LSL#1 	    ;R0 = R2 - (R3 左移一位)
4. SBC 带借位减法指令

汇编格式:SBC{}{S} Rd,Rn,operand2

功能:SBC指令用于把寄存器Rn的值减去操作数operand2,再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器Rd中。即Rd=Rn-operand2-!C, 其中Rd为目的寄存器,Rn为操作数1,必须是一个寄存器,operand2是操作数2,可以是一个寄存器,被移位的寄存器或一个立即数。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志位N、Z、 C、V标志。

例 用SBC指令完成64位减法,设第一个64位操作数0x20000000 50000000放在R2、R3中,第二个64位操作数0x3000000040000000放在R4、R5中。64位结果放在R0、R1中

分析:首先将两个64位数的低32位相减,其结果影响C标志位。此例子中低32位相减必然产生借位,即影响CPSR中的C值,使得C=0,表示有借位。然后将64位数的高32位以及C 位的取反的值相减。

SUBS R0,R2,R4  ;低32位相减,S表示结果影响条件标志位的值
SUC	 R0,R2,R4  ;高32位相减
5. RSB 逆向减法指令

汇编格式:RSB{}{S} Rd,Rn,operand2

功能:RSB指令称为逆向减法指令,指令表示把操作数2减去操作数1,并将结果存放到目的寄存器中。即Rd= operand2-Rn,其中Rn为操作数1,应是一个寄存器,operand2为操作数2,可以是一个寄存器,被移位的寄存器或一个立即数。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志位N、Z、 C、V标志。该指令可用于有符号数或无符号数的减法运算。

例 RSB指令示例:

RSB R0,R1,R2          ;R0 = R2-R1
RSB R0,R1,#6          ;R0 =6-R1
RSB R0,R2,R3,LSL#1    ;R0 = (R3左移一位)-R2
6. RSC带借位的逆向减法指令

汇编格式:RSC{}{S} Rd,Rn,operand2

功 能:RSC指令表示把操作数operand2减去寄存器Rn的值,再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器Rd中。即Rd=operand2-Rn-!C, 其中Rd为目的寄存器,Rn为操作数1,必须是一个寄存器operand2是操作数2,可以是一个寄存器,被移位的寄存器,或一个立即数。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志位N、Z、C、V标志。

例 RSC指令示例:

 RSC R0,R1,R2      ;R0 = R2–R1-!C

6.4 逻辑运算指令

逻辑运算是对操作数按位进行操作的,位与位之间无进位或借位,无数的正负与数的大小之分,这种运算的操作数称为逻辑数或逻辑值。逻辑运算指令主要包括:

  • AND 逻辑与指令

  • ORR 逻辑或指令

  • EOR 逻辑异或指令

  • BIC 位清除指令

1. AND 逻辑与指令

汇编格式:AND{}{S} Rd,Rn,operand2

功能:AND指令将两个操作数按位进行逻辑与运算,结果放置到目的寄存器Rd中。即Rd=Rn AND operand2,其中Rn为操作数1,是一个寄存器,operand2为操作数2,可以是一个寄存器,被移位的寄存器或一个立即数。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志位N和Z值,在计算第2操作数时更新标志C,不影响V标志。该指令常用于将操作数1的特定位清零的操作,所谓将某位清零就是将该位置0。

例 设R0=0xFFFFFFFF,则执行下列指令后R0的值是多少?

AND R0,R0,#0xF                 

分析:执行后R0 = 0x0000000F

2. ORR 逻辑或指令

汇编格式:ORR{}{S} Rd,Rn,operand2

功 能:ORR指令将两个操作数按位进行逻辑或运算,结果放置到目的寄存器Rd中。即Rd=Rn OR N,其中Rn为操作数1,是一个寄存器, operand2为操作数2,可以是一个寄存器,被移位的寄存器或一个 立即数。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志位N和Z值,在计算第2操作数时更新标志C,不影响V标志。该指令常用于将操作数1的特定位置位的操作,所谓将特定位置位就是将该位置1。

例 R0的第0位和第3位设置为1,其余位不变

ORR   R0,R0,#5
3. EOR 逻辑异或指令

汇编格式:EOR{}{S} Rd,Rn,operand2

功 能:EOR指令将两个操作数按位进行逻辑异或运算,并把结果放置到目的寄存器Rd中。即Rd=Rn EOR operand2,其中Rn为操作数1,是一个寄存器,operand2为操作数2,可以是一个寄存器、被移位的寄存器或一个立即数。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志
位N和Z值,在计算第2操作数时更新标志C,不影响V标志。该指令常用于反转操作数1的某些位。

例 将R0的低4位取反,其余位不变

EOR  R0,R0,#F
4. BIC 位清除指令

汇编格式:BIC{}{S} Rd,Rn,operand2

功能:BIC指令用于清除操作数Rn的某些位,并把结果放置到目的寄存器Rd中。即Rd=Rn AND (!operand2),其中Rn为操作数1,是一个寄存器,operand2为操作数2,可以是一个寄存器,被移位的寄存器,或一个立即数。这里operand2可以看作一个32位的掩码,如果在掩码中设置了某一位,则清除Rn中相应的位。未设置掩码位的则Rn中相应位保持不变。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志位N和Z值,在计算第2操作数时更新标志C,不影响V标志。

例 将R0的第0位和第3位清0,其余位不变

BIC   R0,R0,#9

6.5 比较指令

比较指令通常用于把一个寄存器与一个32位的值进行比较或测试。比较指令根据结果更新CPSR中的标志位,但不影响其它的寄存器。在设置标志位 后,其它指令可以通过条件执行来改变程序的执行顺序。对于比较指令,不需要使用S后缀就可以改变标志位的值。比较指令包括:

  • CMP 比较指令

  • CMN 反值比较指令

  • TST 位测试指令

  • TEQ 相等测试指令

1. CMP比较指令

汇编格式:CMP{}{S} Rn,operand2

功能:CMP指令将寄存器Rn的内容和另一个操作数operand2进行比较,同时更新CPSR中条件标志位的值。该指令实质上是进行一次减法运算,但不存储结果,只更改条件标志位。后面的指令就可以根据条件标志位来决定是否执行。例如,当操作数Rn大于操作操作数operand2时,执行CMP指令后,则此后带有GT 后缀的指令将可以执行。

CMP指令示例:

CMP R1,#10       ;将寄存器R1的值与10相减,并设置CPSR的标志位
ADDGT R0,R0,#5    ;如果R1>10,则执行ADDGT指令,将R0加5
2. CMN反值比较指令

汇编格式:CMN{}{S} Rn,operand2

功 能:CMN指令用于把一个寄存器Rn的内容和另一个操作数operand2取反后进行比较,同时更新CPSR中条件标志位的值。该指令实际上是将操作数Rn和操作数operand2相加,并根据结果更改条件标志位。同样,后面的指令就可以根据条件标志位来决定是否执行。

CMN指令示例:

CMN  R0,R1    ;将寄存器R0的值与寄存器R1的值相加,
              ;并根据结果设置CPSR的标志位
CMN  R0,#10  ;将寄存器R0的值与立即数10相加,
              ;并根据结果设置CPSR的标志位
3. TST位测试指令

汇编格式:TST{}{S} Rn,operand2

功能:TST指令用于把一个寄存器Rn的内容和另一个操作数operand2按位进行与运算,并根据运算结果更新CPSR中条件标志位的值。该指令通常用来检查是否设置了特定的位。其中操作数Rn是要测试的数据,这里操作数operand2可以看作一个32位的掩码,如果在掩码中设置了某一位,表示检查该位。未设置的掩码位则表示不检查。

例 如要检查R0中的第0位和第1位是否为1则应执行什么指令?
分析:检查R0 中的第0位和第1位是否为1则不应改变R0的值,因此执行如下指令:

TST    R1,#3	
4. TEQ相等测试指令

汇编格式:TEQ{}{S} Rn,operand2

功 能:TEQ指令用于把一个寄存器Rn的内容和另一个操作数operand2按位进行异或运算,并根据运算结果更新CPSR中条件标志位的值。该指令通常用于比较操作数Rn和操作数operand2是否相等。

TEQ指令示例:

TEQ  R1,R2     ;将寄存器R1的值与寄存器R2的值按位异或,
                ;并根据结果设置CPSR的标志位

6.6 乘法指令

乘法指令把一对寄存器的内容相乘,然后根据指令类型把结果累加到其它的寄存器。 ARM微处理器支持的乘法指令与乘加指令共有6条,根据运算结果可分为32位运算和64位运算两类。64位乘法又称为长整型乘法指令,由于结果太大,不能在放在一个32位的寄存器中,所以把结果存放在2个32位的寄存器Rdlo和Rdhi中。Rdlo存放低32
位,Rdhi存放高32位。与前面的数据处理指令不同,指令中的所有源操作数、目的寄存器必须为通用寄存器,不能对操作数使用立即数或被移位的寄存器。同时,目的寄存器Rd和操作数Rm必须是不同的寄存器。乘法指令与乘加指令共有以下6条:

  • MUL 32位乘法指令
  • MLA 32位乘加指令
  • SMULL 64位有符号数乘法指令
  • SMLAL 64位有符号数乘加指令
  • UMULL 64位无符号数乘法指令
  • UMLAL 64位无符号数乘加指令
1. MUL 32位乘法指令

汇编格式:MUL{}{S} Rd,Rm,Rs

功能:MUL指令完成将操作数Rm与操作数Rs 的乘法运算,并把结果放置到目的寄存器Rd中,即Rd=Rm×Rs。S选项决定指令的操作是否影响CPSR中条件标志位的值,有S时指令执行后的结果影响CPSR中条件标志位N和Z值,在ARMv4及以前版本中,标志 C和V不可靠,在ARMV5及以后版本中不影响C和V标志(以下几个乘法指令对于S的规定与此相同)。

MUL指令示例:

MUL R0,R1,R2   ;R0 = R1 × R2
MULS R0,R1,R2     ;R0 = R1 × R2,同时设置CPSR中的相关条件标志位
2. MLA 32位乘加指令

汇编格式:MLA{}{S} Rd,Rm,Rs,Rn

功能:MLA指令完成将操作数Rm与操作数Rs的乘法运算,再将乘积加上Rn,并把结果放置到目的寄存器Rd中,即Rd=(Rm×Rs)+Rn。如果书写了S,同时根据运算结果设置CPSR中相应的条件标志位。

MLA指令示例:

MLA  R0,R1,R2,R3  ;R0 = R1× R2+ R3
MLAS  R0,R1,R2,R3  ;R0 = R1× R2+ R3,同时设置CPSR中的相关条件标志位
3. SMULL 64位有符号数乘法指令

汇编格式:SMULL{}{S} Rdlo,Rdhi,Rm,Rs

​ 功 能:SMULL指令实现32位有符号数相乘,得到64位结果。32操作数Rm与32操作数Rs作乘法运算,并把结果的低32位放置到目的寄存器Rdlo中,结果的高32位放置到目的寄存器Rdhi中,即[Rdhi Rdlo]=Rm×Rs。如果书写了S,同时根据运算结果设置CPSR中相应的条件标志位。其中,操作数Rm和操作数Rs均为32位的有符号数。

SMULL指令示例:

SMULL R0,R1,R2,R3  ;R0 = (R2×R3)的低32位  Rdlo
                       ;R1 = (R2×R3)的高32位  Rdhi
4. SMLAL 64位有符号数乘加指令

汇编格式:SMLAL{}{S} Rdlo,Rdhi,Rm,Rs

功能:SMLAL指令实现32位有符号数相乘并累加,得到64位结果。32位操作数Rm与32位操作数Rs作乘法运算,并把结果的低32位同目的寄存器Rdlo中的值相加后又放置到目的寄存器Rdlo中,结果的高32位同目的寄存器Rdhi中的值相加后又放置到目的寄存器Rdhi中,即[Rdhi Rdlo]= [Rdhi Rdlo]+Rm×Rs。如果书写了S,同时根据运算结果设置CPSR中相应的条件标志位。其中,操作数Rm和操作数Rs均为32位的有符号数。对于目的寄存器Rdlo ,在指令执行前存放64位加数的低32位,指令执行后存放结果的低32位。对于目的寄存器Rdhi,在指令执行前存放64位加数的高32位,指令执行后存放结果的高32位。

SMLAL指令示例指令示例:

SMLAL R0,R1,R2,R3  ;R0 = (R2×R3)的低32位 + R0   Rdlo
                    ;R1 = (R2×R3)的高32位 + R1   Rdhi
5. UMULL 64位无符号数乘法指令

汇编格式:UMULL{}{S} Rdlo,Rdhi,Rm,Rs

功能:UMULL指令实现32位无符号数相乘,得到64位结果。32操作数Rm与32操作数Rs作乘法运算,并把结果的低32位放置到目的寄存器Rdlo中,结果的高32位放置到目的寄存器Rdhi中,即[Rdhi Rdlo]=Rm×Rs。如果书写了S,同时根据运算结果设置CPSR中相应的条件标志位。其中,操作数Rm和操作数Rs均为32位的无符号数。

UMULL指令示例:

UMULL  R0,R1,R2,R3 ;R0 =(R2×R3)的低32位  Rdlo
                   ;R1 =(R2× R3)的高32位  Rdhi
6. UMLAL 64位无符号数乘加指令

汇编格式:UMLAL{}{S} Rdlo,Rdhi,Rm,Rs

功 能:UMLAL指令实现32位无符号数相乘并累加,得到64位结果。

UMLAL指令示例指令示例:

 UMLAL R0,R1,R2,R3 	;R0 = (R2×R3)的低32位 + R0   Rdlo
						;R1 = (R2×R3)的高32位 + R1   Rdlo

使用乘法指令应该注意如下事项

  • 在操作中使用寄存器,但R15不可用。

  • 在寄存器的使用中,注意Rd不能同时作为Rm,其它无限制。

  • 有符号运算和无符号运算的低32位是没有区别的。

  • Rdlo、Rdhi和Rm必须使用不同的寄存器

  • 对于UMULL和UMLAL,即使操作数的最高位为1,也解释为无符号数

    例 下列指令都是错误的:

    MUL R1,R1,R6 	;错误,目标寄存器R1不能同时作第一个操作数
    MUL R1,R6,[R5]	;错误,不能使用[]
    MLA R4,R5,R6	;错误,少1个操作数
    MULSNE R6,R3,R0 ;错误,应该写成MULNES
    UMLAL R6,R4,R4,R1 ;错误,R4不能同时作Rdlo、Rdlo
    SMULL R5,R3,R0  ;错误,少1个操作数
    MUL R2,R5,#0x20 ;错误,不可用立即数
    

7. 数据加载与存储指令

7.1数据加载与存储指令概述

ARM处理器是加载/存储体系结构的处理器,对存储器的访问只能通过加载和存储指令实现。

  • 数据加载与存储的方向问题

    数据加载与存储(Load-store)指令用于在存储器和处理器的寄存器之间传送数据。如图3-18所示,Load用于把内存中的数据装载到寄存器中,而Store则用于把寄存器中的数据存入内存。在这里插入图片描述

    数据加载与存储指令共有三种类型:

    • 单寄存器加载与存储指令

    • 多寄存器加载与存储指令

    • 交换指令。

  • 数据加载与存储指令的寻址

    数据加载与存储类指令的基本格式为 opcode{} Rd,addr。格式中opcode为指令代码,如LDR表示将存储器中的数据加载到寄存器中。addr为存储器的地址表达式,也称为第2操作数,可表示为[Rn,offset],其中Rn表示基址寄存器,offset表示偏移量。Addr有如下几种表示形式:

    • 立即数
      立即数可以是一个无符号的数值,这个数值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。如:

      LDR R5,[R6,#0x08]
      STR R6,[R7],#-0x08
      
    • 寄存器
      寄存器中的数值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。如:

    LDR R5,[R6,R3]
    STR R6,[R7],-R8
    
    • 寄存器移位
      这种格式由一个通用寄存器和一个立即数组成,寄存器中的数值可以根据指令中的移位标志以及移位常数作一定的移位操作,生成一个地址偏移量。这个地址偏移量可以加到基址寄存器,也可以从基址寄存器中减去这个数值。如:

      LDR R3,[R2,R4,LSL#2]  
      LDR R3,[R2],-R4,LSR#3
      
    • 标号
      这是一种简单的寻址方法。在这种方法中,程序计数器PC是隐含的基址寄存器,偏移量是语句标号所在的地址和PC(当前正在执行的指令)之间的差值。例如:

      LDR R4,START 
      
  • 地址索引

    ARM指令中的地址索引也是指令的一个功能,索引作为指令的一部分,它影响指令的执行结果。地址索引分为前索引(Pre-indexed)、自动索引(Auto-indexed)和后索引(Post-indexed)。

    • 前索引

    前索引也称为前变址,这种索引是在指令执行前把偏移量和基址相加/减,得到的值作为寻址的地址。例如:

    LDR R5,[R6,#0x04]
    STR R0,[R5,-R8]
    

    在上述第1条指令中,在寻址前先把R6加上偏移量4,作为寻址的地址值;在第2条指令中,在寻址前先把基址R5和偏移量R8相减,以计算的结果作为地址值。在这两条指令中,指令完成后,基址寄存器的地址值和指令执行前相同,并不发生变化。

    在上述第1条指令中,在寻址前先把R6加上偏移量4,作为寻址的地址值;在第2条指令中,在寻址前先把基址R5和偏移量R8相减,以计算的结果作为地址值。在这两条指令中,指令完成后,基址寄存器的地址值和指令执行前相同,并不发生变化。

    • 自动索引

    自动索引也称为自动变址,有时为了修改基址寄存器的内容,使之指向数据传送地址,可使用这种方法自动修改基址寄存器。例如:

    LDR R5,[R6,#0x04]!
    

    这条指令在寻址前先把R6加上偏移量4,作为寻址的地址值,通过可选后缀“!”完成基址寄存器的更新,本例中执行完操作后R6(基址寄存器)的内容加4。

    这条指令在寻址前先把R6加上偏移量4,作为寻址的地址值,通过可选后缀“!”完成基址寄存器的更新,本例中执行完操作后R6(基址寄存器)的内容加4。

    • 后索引
      后索引也称为后变址,后索引就是用基址寄存器的地址值寻址,找出操作数进行操作,操作完成后,再把地址偏移量和基址相加/减,结果送到基址寄存器,作为下一次寻址的基址。例如:

      LDR R5,[R6],#0x04
      STR R6,[R7],#-0x08
      

      在上述指令中,先把R6指向的地址单元的数据赋给R5,再把偏移量4加到基址寄存器R6中去;在第2条指令中,先把R6的值存储到R7指向的地址单元中去,再把偏移量-8加到R7上。在后索引中,基址在指令的执行前后是不相同的。

      在上述指令中,先把R6指向的地址单元的数据赋给R5,再把偏移量4加到基址寄存器R6中去;在第2条指令中,先把R6的值存储到R7指向的地址单元中去,再把偏移量-8加到R7上。在后索引中,基址在指令的执行前后是不相同的。

不同索引方式的区别

  • 前索引和自动索引的区别是:前索引方式利用对基址寄存器的改变值进行寻址,但是基址寄存器在操作之后仍然保持原值。自动索引在计算出新的地址后要用新的地址更新基址寄存器的内容,然后再利用新的基址寄存器进行寻址;

  • 前索引和后索引的区别:前索引在指令执行完成后并没有改变基址寄存器的值,后索引在指令执行完成后改变了基址寄存器的地址值。
    后索引和自动索引的区别:后索引和自动索引类似,也要更新基址寄存器的内容,但是变址方式先利用基址寄存器的原值进行寻址操作,然后再更新基址寄存器。这两种方式在遍历数组时是很有用的。

7.2单寄存器加载与存储指令

这种指令用于把单一的数据传入或者传出一个寄存器。支持的数据类型有字(32位)、半字(16位)和字节。常用的单寄存器加载与存储指令包括:

  • LDR/STR 字数据加载/存储指令

  • LDRB/STRB 字节数据加载/存储指令

  • LDRH/STRH 半字数据加载/存储指令

  • LDRSB/LDRSH 有符号数字节/半字加载指令

1. LDR/STR字数据加载/存储指令

LDR/STR指令的格式和功能如下 :

机器编码格式:LDR/STR指令的机器编码格式如图所示

在这里插入图片描述

其中:

  • cond: 指令执行的条件编码

  • I、P、U、W: 用于区别不同的地址模式(偏移量)。I为0时,偏移量为12位立即数;I 为1时,偏移量为寄存器移位

  • P表示前/后索引

  • U表示加/减

  • W表示回写

  • L: L为1表示加载,L为0表示存储。

  • B: B为1表示字节访问,B为0表示字访问

  • Rd: 源/目标寄存器

  • Rn: 基址寄存器

  • addr_mode: 表示偏移量,是一个12位的无符号二进制数,与Rn一起构成地址 addr

汇编格式:LDR{}{T} Rd,addr

功能:LDR指令用于从存储器中将一个32位的字数据加载到目的寄存器Rd中。该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。

LDR指令示例:

;使用标号
LDR R4,START          ;将存储地址为START的字数据读入R4   
STR R5,DATA1          ;将R5存入存储地址为DATA1中

;前索引
LDR R0,[R1]            ;将存储器地址为R1的字数据读入寄存器R0。
LDR R0,[R1,R2]         ;将存储器地址为R1+R2的字数据读入寄存器R0。
LDR R0,[R1,#8]        ;将存储器地址为R1+8的字数据读入寄存器R0。
LDR R0,[R1,R2,LSL#2] ;将存储器地址为R1+R2×4的字数据读入寄存器R0。

;自动索引
STR R0,[R1,R2]!      ;将R0字数据存入存储器地址为R1+R2的存储单元
						;中,并将新地址R1+R2写入R1。
STR R0,[R1,#8]!      ;将R0字数据存入存储器地址为R1+8的存储单元中,
						;并将新地址R1+8写入R1
STR R0,[R1,R2,LSL#2]!;将R0字数据存入地址为R1+R2×4的存储单元中
						;并将新地址R1+R2×4写入R1。
						
;后索引
LDR R0,[R1],#8     		;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+8写入R1
LDR R0,[R1],R2			;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1],R2,LSL#2  ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。

注意事项:

  • 立即数的规定
    立即数绝对值不大于4095的数值,可使用带符号数,即在-4095~+4095之间。

  • 标号使用的限制 要注意语句标号不能指向程序存储器的程序存储区,而是指向程序存储器 的数据存储区或数据存储器的数据存储区。另外指向的区域是可修改的,例如,在用户模式下,有些存储区是不能访问的或是只读的。

  • 地址对齐
    字传送时,偏移量必须保证偏移的结果能够使地址对齐。

  • 使用移位时需注意
    使用寄存器移位的方法计算偏移量时,移位的位数不能超过规定的数值。各类移位指令的移位位数规定如下:
    ASR #n:算术右移(1≤n≤32)
    LSL #n:逻辑左移(0≤n≤31)
    LSR #n:逻辑右移(1≤n≤32)
    ROR #n:循环右移 (1≤n≤31)

  • 注意程序计数器R15
    R15作为基址寄存器Rn时,不可以使用回写功能,即使用后缀“!”。另外,R15不可作为偏移寄存器使用。

针对以上注意事项,在书写汇编指令时要注意指令的正误问题,如下所示。

LDR R1,[R2,R5]!         ;正确
STR R2,[R3],#0xFFFF8    ;错误,超出了立即数的范围
STREQ R4,[R0,R4,LSL R5] ;错误,不能用寄存器表示移位的位数
LDR R4,[R0,R1,LSL #32]  ;错误,超出了移位的范围
STREQ R3,[R6],#-0x08    ;正确
LDR R0,[R2]!,-R6        ;错误,后索引不用!后缀
LDR R4,START            ;正确
LDR R1,[SP,#-0x04]      ;正确
STR R1,START            ;格式正确,但必须保证标号处可以存储数据
LDR PC,R6               ;错误,R6不表示一个存储地址
LDR PC,[R6]             ;正确
LDR R1,[R3,R15]         ;错误,R15不可作为偏移寄存器
2. LDRB/STRB 字节数据加载/存储指令

指令的格式和功能如下:
机器编码格式:LDRB/STRB指令的机器编码格式如图所示

在这里插入图片描述

汇编格式: LDRB/STRB {}{T} Rd,addr

功能: LDRB指令用于从存储器中将一个8位的字节数据加载到目的寄存器中,同时将寄存器的高24位清零。该指令通常用于从存储器中读取8位的字节数据到通用寄存器,然后对数据进行处理。当程序计数器 PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。

STRB指令用于从源寄存器中将一个8位的字节数据存储到存储器中。该字节数据为源寄存器中的低8位。STRB指令和LDRB指令的区别在于数据的传送方向。

后缀T为可选后缀,若指令中有T,那么即使处理器是在特权模式下,存储系统也将访问看成是处理器是在用户模式下。T在用户模式下无效,不能与前索引一起使用。

必须明确的是:即使传送的是8位数据,地址总线仍然以32位的宽度工作,而数据总线也是以32位的宽度工作,传送16位的半字数据,地址总线 和数据总 线也是以32位的宽度工作的,字节传送过程和字传送过程相差很大,下面详细说明。

  • 从寄存器存储到存储器的过程
    由于寄存器中的数据是32位结构,在向存储器存储8位字节时,怎样去选择寄存器中4个字节中的一个字节呢?在ARM指令中,从寄存器到存储器的一字节数据存储只能传送最低8位,即最低字节[7:0]。如果想要存储其它字节,可以采用移位的方法把要存储的字节移至最低字节。从寄存器到存储器的8位字节传送如图所示。在这里插入图片描述

  • 从存储器到寄存器的加载过程
    和上述不同的是,在实现从存储器到寄存器的加载过程时,可以选择任何一个存储器的地址单元,这时是不要求地址对齐的。也就是说,可以不加限制地选择任何存储器中的字节加载。从存储器到寄存器的8位字节传送如图所示。

在这里插入图片描述

LDRB/STRB指令示例:

LDRB R0,[R1]        ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。
LDRB R0,[R1,#8]    ;将存储器地址为R1+8的字节数据读入寄存器R0,并将R0的高24位清零。
STRB R0,[R1]        ;将寄存器R0中的字节数据写入以R1,为地址的存储器中。
STRB R0,[R1,#8]    ;将寄存器R0中的字节数据写入以R1+8为地址的存储器中。
  • LDRH/STRH半字数据加载/存储指令
    机器编码格式:LDRH/STRH半字数据加载/存储指令的机器编码格式如图所示。

在这里插入图片描述

图中各位的含义如下:

  • cond: 指令执行的条件编码

  • I、P、U、W: 用于区别不同的地址模式(偏移量)。I为0时,偏移量为8位立即数;I为1时,偏移量为寄存器移位。P表示前/后变址,U表示加/减,W表示回写。

  • L: L为1表示加载,L为0表示存储。

  • S: 用于区别有符号访问(S为1)和无符号访问(S为0)

  • H: 用于区别半字访问(H为1)或字节访问(H为0)

  • Rd: 源/目标寄存器

  • Rn: 基址寄存器

  • addr_H addr_L: 表示偏移量, I为0时,偏移量为8位立即数由addr_H和addr_L组成;I为1时,偏移量为寄存器移位addr_H为0,addr_L表示寄存器编号。

  • 汇编格式:

    LDRH/STRH{} Rd,addr

功能:LDRH指令用于从存储器中将一个16位的半字数据加载到目的寄存器Rd中,同时将寄存器的高16位清零。该指令通常用于从存储器中读取16位的半字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。

LDRH/STRH指令示例:

LDRH R0,[R1]   ;将存储器地址为R1的半字数据读入寄存器R0,并将R0的高16位清零。
LDRH R0,[R1,#8]  ;将存储器地址为R1+8的半字数据读入寄存器R0,并将R0的高16位清零。
LDRH R0,[R1,R2]   ;将存储器地址为R1+R2的半字数据读入寄存器R0,并将R0的高16位清零。
STRH R0,[R1]   ;将寄存器R0中的半字数据写入以R1为地址的存储器中。

使用半字加载/存储指令需要注意如下事项:

  • 必须半字地址对齐。
  • 对于R15的使用需要慎重,R15作为基址寄存器Rn时,不可以使用回写功能;不可使用R15作为目的寄存器。
  • 立即数偏移使用的是8位无符号数。
  • 不能使用寄存器移位寻址
4. LDRSB/LDRSH 有符号数字节/半字加载指令

机器编码格式:LDRSB/STRSH指令的机器编码格式如图所示。

在这里插入图片描述

汇编格式:LDRSB/LDRSH{} Rd,addr

功能:LDRSB指令用于从存储器中将一个8位的字节数据加载到目的寄存器中,同时将寄存器的高24位设置为该字节数据的符号位的值,即将该8 位字节 数据进行符号位扩展,生成32位数据。

LDRSH指令用于从存储器中将一个16位的半字数据加载到目的寄存器Rd中,同时将寄存器的高16位设置为该字数据的符号位的值,即将该16位字数据进行符号位扩展,生成32位数据。

LDRSB/LDRSH指令示例

LDRSB R0,[R1,#4] ;将存储地址为R1+4的有符号字节数据读入R0,R0中的高24位设置成该字节数据的符号位。
LDRSH R6,[R2],#2 ;将存储地址为R2+2的有符号半字数据读入R6,R6中的高16位设置成该字节数据的符号位         			 ;R2=R2+2

7.3多寄存器加载与存储指令

多寄存器加载与存储指令也称为批量数据加载/存储指令,ARM微处理器所支持批量数据加载/存储指令可以一次在一片连续的存储器单元和多个寄存器之间传送数据,批量加载指令用于将一片连续的存储器中的数据加载到多个寄存器,批量数据存储指令则完成相反的操作。

多寄存器加载与存储指令在数据块操作、上下文切换、堆栈操作等方面,比单寄存器加载与存储指令会有更高的执行效率。常用的加载存储指令有LDM和STM指令。

1. LDM/STM批量数据加载/存储指令

机器编码格式:LDM/STM指令的机器编码格式如图所示

在这里插入图片描述

图中各位的含义如下:

  • cond: 指令执行的条件编码
  • P、U、W: 用于区别不同的地址模式(偏移量)。P表示前/后变址,U表示加/减,W表示回写。
  • S: 用于区别有符号访问(S为1)和无符号访问(S为0)。
  • L: L为1表示加载,L为0表示存储。
  • Rn: 基址寄存器
  • regs: 表示寄存器列表

汇编格式:LDM/STM{}{} Rn{!},{∧}

功能:LDM指令用于从基址寄存器所指示的一片连续存储器中读取数据到寄存器列表所指示的多个寄存器中,内存单元的起始地址为基址寄存器Rn的值,各个寄存器由寄存器列表regs表示。该指令一般 用于多个寄存器数据的出栈操作。

STM指令用于将寄存器列表所指示的多个寄存器中的值存入到由基址寄存器所指示的一片连续存储器中,内存单元的起始地址为基址寄存器Rn的值,各 个寄存器由寄存器列表regs表示。指令的其它参数的用法和LDM指令是相同的。该指令一般用于多个寄存器数据的进栈操作。

指令中,type表示类型,用于数据的存储与读取有以下几种情况:

  • IA每次传送后地址值加
  • IB每次传送前地址值加
  • DA每次传送后地址值减
  • DB每次传送前地址值减
  • 用于堆栈操作时有如下几种情况:
  • FD 满递减堆栈
  • ED 空递减堆栈
  • FA满递增堆栈
  • EA空递增堆栈

{!}为可选后缀,若选用该后缀,则当数据加载与存储完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。基址寄存器不允许为R15,寄存器列表可以为R0~R15的任意组合。

{∧}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据加载与存储之外,还将SPSR复制到CPSR。同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。
LDM/STM指令依据其后缀名(如IA、IB)的不同,其寻址的方式也有很大不同。具体如表所示

在这里插入图片描述

从表中可以看出,指令分为两组:一组用于数据的存储与读取,对应于IA、IB、DA、DB;一组用于堆栈操作,即进行压栈与出栈的操作,对应于FD、ED、FA、EA。

2. LDM/STM指令寻址的区别

下图给出了数据块操作的用法,从图中可以看出,每条指令是如何将4个寄存器的数据存入存储器的,以及在使用自动变址的情况下基址寄存器是如何变化的。执行指令之前基址寄存器为R0,自动变址之后为R0’。需要注意的是,在递增方式下(即图中的IA、IB方式),寄存器存储的顺序是R1、R2、R3、R4;而在递减方式下(即图中的DA、DB方式),寄存器存储的顺序是R4、R3、R2、R1。

在这里插入图片描述

【例】 设执行前:R0=0x00090010、R6=R7=R8=0x00000000,存储器地址为0x00090010存储的内容如图1所示

在这里插入图片描述

​ 图1 指令执行前

则分别执行指令

LDMIA R0!,{R6-R8}
LDMIB R0!,{R6-R8}
各相关寄存器值的变化分别如何?

分析:指令"LDMIA R0!,{R6-R8}"的执行过程如下:以R0的值(0x00090010)为基地址取出一个32位数据(0x00000001)放入寄存器R6,然后R0的值加4写回到R0,继续取出一个32位数据放入R7,一次类推,最后执行完的结果如图2所示:

在这里插入图片描述

​ 图2 LDMIA指令执行后

指令LDMIB R0!,{R6-R8}的执行过程如下:以R0的值加4 (0x00090014)为基址取出一个32位数(0x00000002)放入寄存器R6,然后将地址值(0x00090014)写回到R0,继续取出一个32位数据放入R7,依次类推,最后LDMIB R0!,{R6-R8}指令执行完后各寄存器的值如图3所示

在这里插入图片描述

​ 图3 LDMIB指令执行后

通过以上例子可以比较出IA和IB的区别:IA是每次取值后增加地址值,IB是每次地址值增加后再取值。同理可以得出DA和DB的区别,只不过此时地址值不是做加法,是做减法而已。

7.4 堆栈操作

  • 堆栈概念:

堆栈就是在RAM存储器中开辟(指定)的一个特定的存储区域,在这个区域中,信息的存入(此时称为推入)与取出(此时称为弹出)的原则不再是“随机存取”,而是按照“后进先出”的原则进行存取。我们称该“存储区”为堆栈。

按照上述定义,我们可以把堆栈想像成一个开口朝下的容器。堆栈的构造如图所示。

在这里插入图片描述

堆栈的一端是固定的,另一端是浮动的。堆栈固定端是堆栈的底部,称为栈底。堆栈浮动端可以推入或弹出数据。向堆栈推入数据时,新推入的数据堆放在以前推入数据的上面,而最先推入的数据被推至堆栈底部,最后推入的 数据堆放在堆栈顶部,这称为栈顶。从堆栈弹出数据时,堆栈顶部数据最先弹出,而最先推入的数据则是最后弹出。

由于堆栈顶部是浮动的,为了指示现在堆栈中存放数据的位置,通常设置一个堆栈指针SP(R13),它始终指向堆栈的顶部。这样,堆栈中数据的进出都由SP来“指挥”。

当一个数据(32位)推入堆栈时,SP(R13的值减4)向下浮动指向下一个地址,即新的栈顶。当数据从堆栈中弹出时,SP(R13的值加4)向上浮动指向新的栈顶。

  • 堆栈操作
    堆栈的操作包括建栈、进栈、出栈三种基本操作。

    1. 建栈
      建栈就是规定堆栈底部在RAM存储器中的位置,如:用户可以通过
      LDR命令设置SP的值来建立堆栈。
      LDR R13,=0x90010
      LDR SP,= 0x90010
      这时,SP指向地址0x90010,栈中无数据,堆栈的底部与顶部是重
      叠,是一个空栈。

    2. 进栈

      ARM体系结构中使用多寄存器指令来完成堆栈操作。出栈使用 LDM指令,进栈使用STM指令。LDM和STM指令往往结合下面一些参数实现堆栈的操作。

  • FD满递减堆栈

    • ED空递减堆栈
  • FA满递增堆栈

    • EA空递增堆栈

    在使用一个堆栈的时候,需要确定堆栈在存储器空间中是向上生长还是向下生长的。向上称为递增(Ascending),向下称为递减(Descending)。

    满堆栈(Full stack)是指堆栈指针SP(R13)指向堆栈的最后一个已使用的地址或满位置(也就是SP指向堆栈的最后一个数据项的位置);相反,空堆栈(Empty stack)是指SP指向堆栈的第一个没有使用的地址或空位置。
    

    ARM制定了ARM-Thumb过程调用标准(ATPCS),定义了例程如何被调用,寄存器如何被分配。在ATPCS中,堆栈被定义为满递减式堆栈,因此LDMFD和STMFD指令分别用来支持POP操作(出栈)和PUSH操作(进栈)。进栈(PUSH)操作就是把数据推入堆栈的操作。ARM中进栈或出栈操作都是以字(32位)为单位的。

    1. 出栈

      出栈(POP)操作就是把数据从堆栈中读出的操作,ARM中使用LDMFD实现出栈的操

    【例】下列指令说明了进栈和出栈的过程,设指令执行之前SP=0x00090010(R13),R4=0x00000003, R3=0x00000002, R2=0x00000001, 将R2-R4入栈,然后出栈,注意进栈和出栈后SP的值?

                       STMFD SP!,{R2-R4}
                       LDMFD SP!,{R6-R8}

分析:第一条指令将R2-R4的数据入栈,指令执行前SP的值为0x00090010,指令执行时SP指向下一个地址(SP-4)存放R4,然后依次存放R3、R2,数据 入栈后SP的值为0x00090004,指向堆栈的满位置,如果有数据继续入栈则下一地址为 0x90000。其过程如图1所示,注意入栈的顺序。

在这里插入图片描述

​ 图1 进栈操作

第二条指令实现退栈操作,在第一条指令的基础上,表示将刚才入栈的数
据分别退栈到R6-R8,退栈后SP指向0x00090010。实际上STMFD指令相
当于STMDB指令,LDMFD指令相当于LDMIA指令。

7.5交换指令

ARM微处理器所支持数据交换指令能在存储器和寄存器之间交换数据。数据交换指令是数据加载与存储指令的一种特例,交换指令是一个原子操作,在操作期间阻止其它任何指令对该存储单元的读/写。 数据交换指令有如下两条:
SWP 字数据交换指令
SWPB 字节数据交换指令
机器编码格式:交换指令的机器编码格式如图所示

在这里插入图片描述

图中各位的含义如下:

  • cond: 指令执行的条件编码
  • B: 表示字交换(B=0)或字节交换(B=1)
  • Rn: 基址寄存器
  • Rd: 目的寄存器
  • Rm: 源寄存器
1. SWP字数据交换指令

汇编格式:SWP{} ,,[]

功能:SWP指令用于将寄存器Rn所指向的存储器中的字数据加载到目的寄存器Rd中,同时将源寄存器Rm中的字数据存储到寄存器Rn所指 向的存储器中,即Rd=[Rn] ,[Rn]=Rm。显然,当寄存器Rm和目的寄存器Rd为同一个寄存器时(两者应与Rn不同),指令交换该寄存器和存储器的内容。

SWP指令示例:

SWP R0,R1,[R2]  ;将R2所指向的存储器中的字数据加载到R0,
				;同时将R1中的字数据存储到R2所指向的存储单元。
SWP R0,R0,[R1]  ;将R1所指向的存储器中的字数据与R0中的字数据交换
2. SWPB字节数据交换指令

汇编格式:SWPB{} ,,[]

功 能:SWPB指令用于将寄存器Rn所指向的存储器中的字节数据加载到目的寄存器Rd中,目的寄存器的高24清零,同时将源寄存器Rm中的字数据存储到寄存器Rn所指向的存储器中。显然,当寄存器Rm和目的寄存器Rd 为同一个寄存器时(两者应与Rn不同),指令交换该寄存器和存储器的内容。

SWPB指令示例:

SWPB R0,R1,[R2] ;将R2所指向的存储器中的字节数据加载到R0,R0的高24位清零
				;同时将R1中的低8位数据存储到R2所指向的存储单元。
SWPB R0,R0,[R1] ;将R1所指向的存储器中的字节数据与R0中的低8位数据交换。

使用SWP和SWPB指令时需要注意:

  • PC不能用作指令中的任何寄存器。
  • 基址寄存器Rn不应与源寄存器Rm或目的寄存器Rd相同,但是Rm和Rd可以相同。
  • 寄存器位置不可为空,必须满足3个寄存器。

8. 分支指令

分支指令是一种很重要的指令,分支指令用于实现程序流程的跳转,这类指令可用来改变程序的执行流程或者调用子程序。

在ARM程序中有两种方法可以实现程序流程的跳转:一种是使用分支指令,另一种是直接向程序计数PC(R15)写入目标地址值。通过向程序计数器PC写入跳转地址值,可以实现在4GB的地址空间中的任意跳转,而使用分支指令,其跳转空间受到限制。

ARMV5E架构指令集中的分支指令如表3-7所示,分支指令可以完成从当前指令向前或向后的32MB的地址空间的跳转。

在这里插入图片描述

1. 分支指令B

B指令的格式和功能如下:
机器编码格式:B和BL分支指令的机器编码格式如图所示。

在这里插入图片描述

图中各位的含义如下:

  • cond: 表示指令执行的条件
  • L: 用来区分分支(L=0)和带返回的分支(L=1)指令。
  • Label: 表示偏移量,是一个24位有符号立即数。

汇编格式:B{} label

功能:B指令是最简单的分支指令。一旦遇到 B 指令,ARM 处理器 将立即跳转到给定的目标地址label,即PC=label,从那里继续执行。这里label表示一个符号地址,它的实际值是相当前PC值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算。它是 24 位有符号数,左移两位后有符号扩展为 32 位,然后与PC值相加,即得到跳转的目的地址。跳转的范围为-32M~+32M。

B指令示例:

backword    SUB  Rl,R1,#1
			CMP  R1,#0      ;比较R1和0 
			BEQ  forward      ;如果R1=0 则跳转到forward处执行
			SUB R1,R2,#3
			SUB R1,R1,#1
forward     ADD R1,R2,#4
			ADD R2,R3,#2
			B backword        ;程序无条件跳转到标号backword处执行

2. 带返回的分支指令BL

BL指令的格式和功能如下:
机器编码格式:机器编码格式如图所示。

在这里插入图片描述

汇编格式:BL{} label

功 能:BL指令是另一个跳转指令,与B指令不同的是:在跳转之前,将PC的当前内容保存在寄存器R14(LR)中保存。因此,可以通过将R14 的内容重新加载到PC中,返回到跳转指令之后的那个指令处执行。该指令用于实现子程序的调用,程序的返回可通过把LR寄存器的值复制到PC寄存器中来实现。

BL指令示例

…
BL func         ;跳转到子程序
ADD R1,R2,#2    ;子程序调用完返回后执行的语句,返回地址
…
func            ;子程序
…               ;子程序代码
MOV R15,R14     ;复制返回地址到PC,实现子程序的返回

分析:该例说明了子程序调用和返回的结构,程序执行到BL语句时,PC指向下一个要执行的语句,此时PC(R15)中的值为下一个语句ADD指令所在的地址。由于BL是一个分支指令,这个指令将改变PC的值使之指向子程序所在的地址,从而调用子程序,子程序调用完后就涉及到程序返回到断点地址重新执行的问题。BL指令不但修改PC的值使之指向子程序,而且还将断点地址保存在LR(R14)寄存器中,此例中即ADD指令所在的地址。子程序的功能实现完后,常常用一个MOV指令将LR(14)中的值复制到PC(R15)中,从而实现了子程序调用的返回功能,其调用关系如图所示。

在这里插入图片描述

​ 图 BL指令实现子程序调用

3. 带状态切换的分支指令BX

BX指令的格式和功能如下:
机器编码格式:机器编码格式如图所示。

在这里插入图片描述

图中各位的含义如下:

  • cond: 指令执行的条件。
  • op: 用来区别BX指令(op=0)和BLX指令(op=1)

汇编格式:BX{} Rm

功 能:BX指令跳转到指令中所指定的目标地址,并实现状态的切换。Rm是一个表达目标地址的寄存器。当Rm中的最低位Rm[0]为1时,强制程序从ARM指令状态跳到Thumb指令状态;当Rm中的最低位Rm[0]为0时,强制程序从Thumb指令状态跳到ARM指令状态。

BX指令示例

CODE32                  ;ARM程序段,32位编码
arm1   ADR R0,thumb1+1  ;伪指令,把语句标号thumb1所在的地址赋给R0,
                        ;末位R0[0]置1,要跳转到THUMB指令集
MOV LR,PC       		;设置返回地址
BX R0           		;跳转
ADD R1,R2,#2    		;返回地址处,第4条指令

CODE16           		;THUMB程序段,16位编码
thumb1 ADD R1,R3,#1     ;THUMB程序
…
BX LR            		;跳转到返回地址处,执行第4条指令

分析:该例说明了带状态切换的子程序调用和返回的结构,ARM程序段执行MOV LR,PC语句时将返回地址保存到了LR寄存器中。执行到BX语句时,PC指向下一个要执行的语句,此时PC(R15)中的值为下一个语句ADD指令所在的地址,并根据R0中的bit[0]实现了由ARM状态切换到Thumb状态。从而调用Thumb子程序,子程序调用完后使用BX LR指令,从而实现了子程 序调用的返回并切换到ARM状态。

4. 带返回和状态切换的分支指令BLX

BLX指令是在ARMv5架构(如ARM1020E)下支持的分支指令

机器编码格式:机器编码格式如图所示

在这里插入图片描述

汇编格式:BLX{} label|Rm

功能:BLX指令跳转到指令中所指定的目标地址,并实现状态的切换,同时将PC(R15)的值保存到LR寄存器(R14)中。其目标地址可以是一个符号地址(label),或者是一个表达目标地址的寄存器Rm。如果目标地址处为Thumb指令,则程序状态从ARM状态切换为Thumb状态。因此,当子程序使用Thumb指令集,而调用者使用ARM指令
集时,可以通过BLX指令实现子程序的调用和处理器工作状态的切换。同时,子程序的返回可以通过将寄存器R14值复制到PC中来完成。

BL指令示例

CODE32           		;ARM程序段,32位编码
arm1  ADR R0,thumb1+1   ;伪指令,把语句标号thumb1所在的地址赋
						;给R0,末位R0[0]置1,要跳转到THUMB指令集
;MOV LR,PC       		;该指令注销 ,比较BL指令
BLX R0         			;跳转,同时设置返回地址 即PCLR
ADD R1,R2,#2    		;返回地址处,第4条指令

CODE16           		;THUMB程序段,16位编码
thumb1 ADD R1,R3,#1     ;THUMB程序
…
BX LR            		;跳转到返回地址处,执行第4条指令

分析:使用BLX指令代替BX指令简化了Thumb例程的调用,因为BLX指令在连接寄存器LR中自动设置了返回地址。比较上例,该例中不需要使用MOV LR,PC指令来保存PC的值了。

9. 程序状态寄存器访问指令

ARM微处理器中的程序状态寄存器不属于通用寄存器,为了使用方便,ARM专门为程序状态寄存器设立了2条访问指令,用于在程序状态寄存器和通用寄存器之间传送数据,程序状态寄存器访问指令如下表所示。

在这里插入图片描述

1. MRS程序状态寄存器到通用寄存器的数据传送指令

机器编码格式:机器编码格式如图所示

在这里插入图片描述

图中各位的含义如下:

  • cond : 指令执行的条件
  • R : 用来区别CPSR(R=0)和SPSR(R=1)。
  • Rd : 表示目标寄存器,Rd不允许为R15。

汇编格式:MRS{},<CPSR|SPSR>

功 能:MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。该指令一般用在以下情况:

  1. 当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用 该指令读出程序状态寄存器的值,然后保存。
  2. 当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。

MRS指令示例:

MRS R0,CPSR	;传送CPSR的内容到R0
MRS R0,SPSR	;传送SPSR的内容到R0

2. MSR通用寄存器到程序状态寄存器的数据传送指令

MRS指令的格式和功能如下:
机器编码格式:机器编码格式如图所示

在这里插入图片描述

图中各位的含义如下

  • cond : 指令执行的条件
  • R : 用来区别CPSR(R=0)和SPSR(R=1)。
  • Field_mask : 域屏蔽
  • immed : 8位立即数
  • Rm : 操作数寄存器

汇编格式:MSR{}<CPSR|SPSR>_,<Rm|#immed>

功能:MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中。其中,状态寄存器是指CPSR或SPSR,一般指当前工作模式下的状态寄存器。操作数可以为通用寄存器Rm或立即数#immed。域用于设
置程序状态寄存器中需要操作的位,32位的程序状态寄存器可分为4个域, 如图所示:

在这里插入图片描述

  • 位[31:24]为条件标志位域,用f表示;
  • 位[23:16]为状态位域,用s表示;
  • 位[15:8]为扩展位域,用x表示;
  • 位[7:0]为控制位域,用c表示;

**位域的表示方法:**在CPSR或SPSR后面使用一下划线,然后是位域。上述位域可以任意组合,之间不用隔点,必须小写才有效。例如CPSR_c和 CPSR_cxsf都是正确的表达式。该指令通常用于恢复或改变程序状态寄存器的内容,在使用时,一般要在MSR指令中指明将要操作的域。

MSR指令示例:

MSR CPSR,R0   ;传送R0的内容到CPSR
MSR SPSR,R0   ;传送R0的内容到SPSR
MSR CPSR_c,R0 ;传送R0的内容到CPSR,仅修改CPSR中的控制位域

将MRS和MSR指令结合起来可以对程序状态寄存器进行修改,从而可以实现处理器模式转换,设置异常中断的开和关。正确的修改方法是对状态寄存器进行读,然后修改,再写入状态寄存器。例如,下列指令序列说明了使能IRQ中断的过程:

MRS R1,CPSR
BIC R1,R1,#0x80
MSR CPSR_c,R1

MRS指令先把CPSR的值复制到R1,然后使用BIC清除R1的位7;再使用MSR把R1的值复制到CPSR,从而实现了使能IRQ中断的功能。这个例子中只是修改了控制域的I位,而没有修改其它位。该例是在SVC模式下执行。在用户模式下可以读取CPSR,但是只能更改条件标志域f。

10. 协处理器指令

协处理器指令用于扩展指令集。协处理器指令既可用于提供附加的计算能力,又可用于控制包括Cache和内存管理的存储子系统。

协处理器指令包括数据处理、寄存器传输及内存传输指令。这里介绍的协处理器指令主要用于ARM处理器初始化、ARM协处理器的数据处理操作、在ARM处理器的寄存器和协处理器的寄存器之间传送数据以及在ARM协处理器的寄存器和存储器之间传送数据。ARM协处理器指令如表3-9所示。

在这里插入图片描述

1. CDP协处理器数据处理指令

CDP指令的格式和功能如下:
机器编码格式:机器编码格式如图所示

在这里插入图片描述

图中各位含义如下:

  • cond: 指令执行的条件
  • opcode1 opcode2: 协处理器将执行的操作。
  • CRm CRn: 存放操作数的协处理器寄存器
  • CRd: 作为目的寄存器的协处理器寄存器
  • p: 协处理器编号,0≤p≤15

汇编格式:CDP{}

,opcode1,CRd,CRm,CRn{,opcode2}

功能:ARM处理器通过CDP指令通知ARM协处理器p,要求其在寄存器CRn 和CRm上,进行操作opcode1,并把结果放到CRd中,可以使用opcode2 提供与操作有关的补充信息。若协处理器不能成功完成特定的操作,则产 生未定义指令异常。指令中的所有寄存器均为协处理器的寄存器,操作由协处理器完成,指令不涉及ARM处理器的寄存器和存储器。

CDP指令示例:

CDP P3,2,C12,C10,C3,4  ;该指令完成协处理器P3的初始化

2. LDC协处理器数据加载指令

LDC指令的格式和功能如下:
机器编码格式:机器编码格式如图所示

在这里插入图片描述

图中各位含义如下:

  • cond : 指令执行的条件
  • P、U、W : 用于区别不同的地址模式。
  • N: 数据的大小(依赖于协处理器)
  • Op : 用于区别LDC指令(op=1)还是STC指令(op=0)
  • Rn : ARM处理器中的作为基地址的寄存器
  • CRd: 作为目的寄存器的协处理器寄存器
  • P : 为协处理器编号,0≤p≤15
  • addr : 8位立即数偏移量

汇编格式:LDC{}{L}

,,

功 能:LDC指令将addr所表示的存储器中的字数据传送到目的寄存器CRd中,若协处理器不能成功完成传送操作,则产生未定义指令异常。其中,{L}选项表示指令为长读取操作,例如:用于双精度数据的传输。addr为存储器的地址表达式,可表示为[Rn,offset],其中Rn表示基址寄存器,是ARM处理器中的寄存器,offset表示偏移量,是一个8位的无符号二进制数。addr的有如下3种表达形式:

  • 偏移为0的地址表达式,如:[R6];
  • 前索引立即数偏移的表达式,如:[R0,#0x04];
  • 后索引立即数偏移的表达式,如:[R4],#0x08。

LDC指令示例:

LDC P5,C1,[R0]  ;将ARM处理器的寄存器R0所指向的存储器中
				;的字数据传送到协处理器P5的寄存器C1中。

3. STC协处理器数据存储指令

STC指令的格式和功能如下:
机器编码格式:机器编码格式如图示

在这里插入图片描述

汇编格式:STC{}{L}

,,

功能:STC指令用于将寄存器CRd的字数据传送到addr所表示的存储器中,若协处理器不能成功完成传送操作,则产生未定义指令异常。STC指令格式中参数的约定和LDC指令格式一致。

STC指令示例:

STC P3,C4,[R0]  ;将协处理器P3的寄存器C4中的字数据传送到ARM
                 ;处理器的寄存器R0所指向的存储器中。

4. MCR ARM处理器寄存器到协处理器寄存器的数据传送指令

MCR指令的格式和功能如下:
机器编码格式:机器编码格式如图所示

在这里插入图片描述

图中各位含义如下:

  • Cond : 指令执行的条件
  • opcode1、opcode2 :协处理器将执行的操作。
  • op : 用于区别MCR指令(op=0)还是MRC指令(op=1)
  • CRm、CRn : 存放操作数的协处理器寄存器
  • Rd : ARM处理器中的作为源或目标的寄存器
  • P : 协处理器编号,0≤p≤15

汇编格式:MCR{}

,opcode1,Rd,CRm,CRn{,opcode2}

功能:MCR指令用于将ARM处理器寄存器Rd中的数据传送到协处理器寄存器CRm,CRn中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码opcode1和opcode2为协处理器将要执行的操作,Rd为源寄存器,是ARM处理器的寄存器,CRm,CRn为目的寄存器,均为协处理器的寄存器。

MCR指令示例:

MCR P5,5,R1,C1,C2,9  ;将ARM处理器寄存器R1中的数据传送到协处理器P5的寄存器C1和C2中,
					;协处理器执行操作5和9。

5.MRC协处理器寄存器到ARM处理器寄存器的数据传送指令

MRC指令的格式和功能如下:
机器编码格式:机器编码格式如图所示

在这里插入图片描述

汇编格式:MRC{}

,opcode1,Rd,CRm,CRn{,opcode2}

功能:MRC指令用于将协处理器寄存器中的数据传送到ARM处理器寄存器中, 若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码opcode1和opcode2为协处理器将要执行的操作,Rd为目的寄存器,是ARM处理器的寄存器,CRm,CRn为源寄存器,均为协处理器的寄存器。

MRC指令示例:

MRC P3,3,R0,C4,C5,6    ;协处理器P3执行操作3和6,操作数为C4、C5,
					   ;其操作的结果传送到ARM处理器寄存器R0中

11. 软件中断指令

ARM指令集中的软件中断指令是唯一一条不使用寄存器的ARM指令,也是一条可以条件执行的指令。

ARM指令在用户模式中受到很大的局限,有一些资源不能访问,在需要访问这些资源时,使用软件控制的唯一可行的方法就是使用SWI(SoftWare Interrupt)指令,也称为软件中断指令。

1. SWI软件中断指令

指令的格式和功能如下:

机器编码格式:机器编码格式如图所示

在这里插入图片描述

图中各位的含义如下:

  • cond : 指令执行的条件
  • swi_num: 24位立即数,表示调用类型。

汇编格式:SWI{} SWI_number

功能:SWI指令用于产生软件中断,以便用户程序能调用操作系统的系统例程。操作系统在SWI的异常处理程序中提供相应的系统服务,指令中SWI_number 为24位的立即数,该数指定用户程序调用系统例程的类型,相关参数通过通用寄存器传递,当指令中24位的立即数被忽略时,用户程序调用系统例程的类型由通用寄存器R0的内容决定,同时,参数通过其它通用寄存器传递。

指令示例:

SWI  0x02 ;该指令调用操作系统编号为02的系统例程。

说明:

  1. 软件中断进入的是管理模式,中断后会改变程序状态寄存器中的相关位。
  2. 中断后处理器把0x00000008赋给PC,并把中断处地址保存在LR 中,把CPSR保存在SPSR中。
  3. SWI_number是向中断服务程序传递一个参数。不需要传递参数时,应该把表达式写作0,表达式不可省略。

2.SWI的调用

当程序执行这条语句时,将进入异常中断。此时,需要把ARM处理器从用户模式改变到管理模式。执行这条指令,ARM处理器硬件会实现下列操作:

  • (1)把中断处的地址值(PC-4)拷贝到R14中,保留中断处地址;
  • (2)把CPSR拷贝到SWI模式的SPSR,保存状态寄存器的值;
  • (3)把状态寄存器的其他模式改变成管理模式;
  • (4)把中断向量0x00000008赋值给PC;
  • (5)禁止IRQ中断,使CPSR[7]=1。随后,程序执行0x00000008处的指令,通常是一个跳转指令或PC赋值指令。

例如:

跳转指令

0x00000008    B INSTART         ;跳转
            …
INTSTART    ADD R4,R5,R0
            …
MOV PC,R14        				;返回

赋值指令

0x00000008   LDR PC, INSTART    ;跳转
            …
INTSTART     ADD R1,R2,R0
             … 
MOV PC,R14         				;返回

在上述例子中,跳转和赋值效果是一样的。执行完中断后使用一条语句返回。在一般情况下,程序会不止一处使用SWI中断指令,程序会从很多中断入口处进入同一个中断服务程序,例如上例中的INTSTART。假如同一个中断服务程序能满足所有中断的要求,那么,上例中的中断服务程序的机构就可以了。但是很多情况下,不同的中断入口会有不同的要求,同一个中断入口因每次进入的条件不同也会有不同的要求。因此,一段服务程序是不够的,往往要有很多不同功能的程序段。

假设把他们编为子功能1、子功能2、…、子功能n,那么软中断的入口INSTART处就应该设置一个向量表,如以下代码。

INTSTART  MOV R0,R0,LSL#2  ;把R0乘以4,R0=功能号×4
ADD PC,PC,R0     ;PCPC+R0
NOP              ;空语句
B  SUBSEG0       ;跳转到功能段0,R0=0时
B  SUBSEG1       ;跳转到功能段1,R0=1时
B  SUBSEG2       ;跳转到功能段2,R0=2时
…
B  SUBSEGn       ;跳转到功能段n,R0=n时

在这个例子中,进入INTSTART后,首先要知道中断所需要的程序功能号,把程序功能号作为地址偏移量赋值给PC,程序就跳转到相应的程序段中去。在上例中,假设R0所存储的是程序功能号,先把这个功能号乘以4(即0号功能指向第0功能偏移为0,1号功能指向第1功能偏移为4,2号功能指向第2功能偏移为8,…),换算成地址偏移,然后加到PC中去。

在上例中,假设R0中是2,也就是说中断要调用2号功能段,在执行第1条语句时,用2乘以4后,R0=8。此时,PC正指向空语句下 面的一条(B SUBSEG0)语句,给PC加8使程序跳转到SUBSEG2。在执行这条语句后,程序跳转到功能段2处。 因此,在这种情况下,程序在中断前,应该存储所需要的功能号;在中断服务程序开始后,再读出这个功能号。这样就实现了一个中断服务程序入口地址的传递。中断时一般有两种方法进行功能号传递(可能还有其他参数需要传递)。
(1)把准备传递的参数通过寄存器进行传递

MOV R0,#0x8   ;使用8号功能段
SWI 0         ;实现中断,不指明调用的功能号

​ (2)用SWI指令传递中断号

 SWI 8         ;实现中断,指明调用的功能号

12. ARM伪指令

ARM伪指令不是ARM指令集中的指令,只是为了编程方便而定义的,伪指令可以象其它ARM指令一样使用,但在编译时这些指令将被等效的ARM指令代替。
ARM伪指令有4条:

  • ADR 小范围的地址读取伪指令
  • ADRL 中等范围的地址读取伪指令
  • LDR 大范围的地址读取伪指令
  • NOP 空操作伪指令

1. ADR 小范围的地址读取伪指令

格 式:ADR{cond} Rm,addr

功 能:ADR指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。

  • Rm:表示要加载的目标寄存器。
  • Addr:地址表达式。当地址值是非字对齐时,取值范围-255~255字节之间;当地址值是字对齐时,取值范围-1020~1020字节之间。对于基于PC相对偏移的地址值时,给定范围是相对当前指令地址后两(ARM7TDMI为三级流水线)。

【例】 使用ADR伪指令加载地址,实现查表功能。

...
ADR R0,ADDR_TAB     ;加载转换表地址
LDRB R1,[R0,R2]     ;使用R2作为参数,进行查表
...
ADDR_TAB  DCB 0xA0,0xF8, 0x80,0x48, 0xE0,0x4F, 0xA3,0xD2

分析:通过ADR伪指令将转换表的首地址值(ADDR_TAB)加载到R0 中,每个表项的偏移地址值由R2传入,从而可以实现查表功能。

2. ADRL 中等范围的地址读取伪指令

格 式:ADRL{cond} Rm,addr

功 能:ADRL指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。ADRL比ADR伪指令可以读取更大范围的地址。在汇编编译源程序时,ADRL伪指令被编译器替换成两条合适的指令。若不能用实现,则产生错误,编译失败。

  • Rm:表示要加载的目标寄存器。
  • Addr:地址表达式。当地址值是非字对齐时,取值范围-64K~64K字节之间;当地址值是字对齐时,取值范围-256K~256K字节之间。

使用ADRL加载地址,可以实现程序跳转,例如:

...
ADR LR,RETURN1       ;设置返回地址
ADRL R1,Thumb_sub+1    ;取得Thumb子程序入口地址,且R1的0位置1
BX R1                  ;调用Thumb子程序,并切换处理器状态
RETURN1  
...

CODE16
Thumb_sub MOV R1,#10
...

3. LDR 大范围的地址读取伪指令

格 式:LDR{cond} Rm,=addr

功 能:LDR指令用于加载32位立即数或一个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV或MVN的范围,则使用MOV或MVN指令代替该LDR伪指令。否则,汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。

格式中:

  • Rm: 表示要加载的目标寄存器。
  • Addr:32位立即数或基于PC的地址表达式或外部表达式。

【例】LDR伪指令举例如下:

LDR R0,=0x12345678     ;加载32位立即数0x12345678
LDR R0,=DATA_BUF+60    ;加载DATA_BUF地址+60
...
LTORG             ;声明文字池
...

伪指令LDR常用于加载芯片外围功能部件的寄存器地址(32位立即数),以实现各种控制操作,如程序:

...
LDR R0,=IOPIN   ;加载GPIO的寄存器IOPIN的地址
LDR R1,[R0]     ;读取IOPIN寄存器的值
...
LDR R0,=IOSET
LDR R1,=0x00500500
STR R1,[R0]          ;IOSET=0x00500500
...

注意:
(1)从PC到文字池的偏移量必须小于4KB。
(2)与ARM指令的LDR相比,伪指令的LDR的参数有“=”号。

4. NOP 空操作伪指令

格式:NOP

功能:NOP伪指令在汇编时将会被代替成ARM中的空操作,比如可能为“MOV R0,R0”指令等。NOP可用于延时操作,如:

...
DELAY
NOP
NOP
NOP
SUBS R1,R1,#1
BNE DELAY1
...

13 . Thumb指令集

1. 概述
2. Thumb指令寄存器的使用
3. ARM-Thumb交互
4. 数据处理指令
5. 单寄存器加载和存储指令
6 . 多寄存器加载和存储指令
7. 堆栈指令
8. 软件中断指令

参考

《ARM体系结构与编程》
《汇编语言程序设计——基于ARM体系结构 (第4版)》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ARMv7体系结构汇总 的相关文章

  • 为什么无符号类型在arm cpu中效率更高?

    我正在阅读手臂手册并提出这个建议 但没有提到原因 为什么无符号类型更快 在 ARMv4 之前 ARM 没有对加载半字和有符号字节的本机支持 要加载有符号的字节 你必须LDRB然后对值进行符号扩展 LSL那就起来吧ASR它回落 这很痛苦所以c
  • 线程安全的向量和字符串容器?

    我之前发过一个问题 在嵌入式 Linux 平台上使用 std string 时出现段错误 https stackoverflow com questions 2412667 seg fault when using stdstring on
  • ARM 汇编 SOS 中的 64 位除法

    我正在计算 16 个 64 位数字相加的平均值 我认为我已经正确完成了所有加法 但现在我需要弄清楚如何将 64 位数字除以 16 但我被困住了 任何帮助都会非常感谢你 到目前为止 这是我的代码 tableSize EQU 16 sum EQ
  • 使用 GCC 编译器为代码的特定部分保留寄存器

    是否可以为 C 代码的特定部分保留寄存器 ffixed reg 选项或声明全局寄存器变量不是我正在寻找的答案 我想保留特定范围 比如说特定函数 的寄存器值 使用局部寄存器变量是不可能的 因为它不能保证在整个范围内保留寄存器的值 我正在寻找类
  • ARM 的启动过程是怎样的?

    我们知道 对于X86架构 按下电源按钮后 机器开始执行0xFFFFFFF0处的代码 然后开始执行BIOS中的代码以进行硬件初始化 BIOS 执行后 它使用引导加载程序将操作系统映像加载到内存中 最后 操作系统代码开始运行 对于ARM架构 使
  • 如何修改内核DTB文件

    Summary 我目前正在为定制板编译 Linux 内核 内核 模块和 DTB 以及一些定制驱动程序 有时 我会编译内核并意识到 DTB 文件中的兼容性字符串不是自定义驱动程序正在寻找的内容 现在 我可以解决此问题的唯一方法是修改 DTS
  • ARM Linux 如何模拟 PTE 的脏位、访问位和文件位?

    As per pgtable 2 level h https git kernel org cgit linux kernel git torvalds linux git tree arch arm include asm pgtable
  • 为 ARM 交叉编译 zlib

    我尝试为arm poky linux gnueabi交叉编译zlib 但启动 make 时出现错误 zlib 1 2 11 AR HOST ar CC HOST gcc RANLIB HOST ranlib configure prefix
  • M1 MacBook Pro 上的 Android Studio 无法使用 ABI armeabi-v7a 模拟系统映像

    我的 M1 Macbook Pro 上的 Android Studio 可以很好地模拟 ABI arm64 v8a 的所有系统映像 API 24 29 30 31 但是 它无法使用 ABI armeabi v7a 运行所有映像 例如 API
  • 在linux x86平台上学习ARM所需的工具[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有一个 x86 linux 机器 在阅读一些关于 ARM 的各种信息时 我很好奇 现在我想花一些时间学
  • 为什么当大小大于 50 时,该程序花费的时间会呈指数级增长?

    所以我正在为类编写一个 ARM 汇编快速排序方法 我对大部分内容都有了解 除了复杂性没有意义 我们将其与我们制作的另一种冒泡排序方法进行比较 它对于具有 1 个参数和 10 个参数的示例表现更好 然而 我什至无法比较 100 个参数测试 因
  • 基于 Windows 8 ARM 的平板电脑上的 VB6

    随着 Windows 8 将支持 VB6 我的问题是 Microsoft 是否在任何地方表示 是或否 VB6 应用程序将在基于 ARM 的平板电脑上运行 如果没有 是否有任何 ARM 模拟器 以便我们可以在 Windows 8 ARM 平板
  • Beaglebone Black 的 U-boot 无法构建 - 目标 CPU 不支持 THUMB 指令

    我正在尝试按照 Chris Simmonds 的 掌握嵌入式 Linux 编程 中的说明为 Beagle Bone Black 构建 u boot 我已经构建了交叉工具链 现在正在尝试使用该工具链构建 Das U boot 但由于不支持 T
  • ARM 系统调用的接口是什么?它在 Linux 内核中的何处定义?

    我读过有关 Linux 中的系统调用的内容 并且到处都给出了有关 x86 架构的描述 0x80中断和SYSENTER 但我无法追踪 ARM 架构中系统调用的文件和进程 任何人都可以帮忙吗 我知道的几个相关文件是 arch arm kerne
  • ARM Chromebook 上的 Android 开发环境?

    我尝试了多次安装和使用安卓工作室 https developer android com studio index html on an ARM Chromebook C100P https archlinuxarm org platfor
  • 设备树不匹配:.probe 从未被调用

    我无法理解设备树的工作原理 或者具体来说为什么该驱动程序无法初始化 这是在 android 版本 3 10 的 rockchip 供应商内核中 驱动程序 看门狗 rk29 wdt c 为了可读性而减少 static const struct
  • 交叉编译armv5,但它创建v7二进制文件

    我设法为arm926ej s创建了一个目标文件我在 qemu 上使用 Debian Arm arm linux gnueabi gcc 4 4 static O c mcpu arm926ej s hello c o hello root
  • 需要一些建议来开始在 ARM(使用 Linux)平台上编程

    我 也许 很快就会在托管 Linux 发行版的 ARM 平台上工作 我不知道哪个发行版 我知道该项目涉及视频流 但我无法告诉你更多信息 其实我只收到通知 还没见到任何人 我从来没有在这样的平台上工作过 所以我的想法是在项目开始之前进行测试
  • Android NDK 代码中的 SIGILL

    我在市场上有一个 NDK 应用程序 并获得了有关以下内容的本机崩溃报告 SIGILL信号 我使用 Google Breakpad 生成本机崩溃报告 以下是详细信息 我的应用程序是为armeabi v7a with霓虹灯支持 它在 NVIDI
  • ARM Cortex-M3 启动代码

    我试图了解 STM32 微控制器的 Keil realview v4 附带的初始化代码是如何工作的 具体来说 我试图了解堆栈是如何初始化的 In the 文档 http infocenter arm com help index jsp t

随机推荐

  • buuctf - web - [极客大挑战 2019]Havefun

    入眼一看 是一只小猫 二话不说 直接F12 根据提示 修改 当前页面 URL 尝试传入参数 直接得flag
  • LWIP-TCP心跳机制

    LWIP TCP心跳机制 简介 在长连接下 可能很长一段时间都没有数据往来 理论上说 这个连接是一直保持连接的 但是实际情况中 如果中间节点出现什么故障是难以知道的 更致命的是 有的节点 防火墙 会自动把一定时间之内没有数据交互的连接给断掉
  • 什么是对网站的base64攻击?

    根据网络安全公司Imperva的一份报告 可以通过Base64编码进行的SQL注入攻击 是最常见的网络应用程序攻击类型之一 占所有攻击的20 这表明 Base64攻击是对网站和网络应用程序的一个重大威胁 Base64是一种常见的编码技术 用
  • 磁盘挂载问题:Fdisk最大只能创建2T分区的盘,超过2T使用parted

    1 下面使用parted工具进行分区的创建 parted dev sdb print 查看分区的使用情况 mklabel gpt 将MBR分区形式转换为GPT分区形式 mkpart promary ext4 划分一个采用ext4文件系统的主
  • SQL SUM() 函数

    SUM 函数返回数值列的总数 SQL SUM 语法 SELECT SUM column name FROM table name WHERE condition column name 是要计算总和的列名 table name 是包含要计算
  • 【学习笔记】感知机模型

    感知机 Perceptron 概述 1957年被提出 是一种有单层计算单元的神经网络模型 在结构上与M P模型相似 提出初衷是解决数据的分类问题 感知机是神经网络和支持向量机的基础 感知机原理 感知机本身是一种能进行二分类的线性模型 只要被
  • mysql为什么使用b+树

    MySQL 使用 B 树有以下几个原因 查询效率高 B 树的查询时间复杂度是 log n 级别的 相比链表和二叉树的 O n 性能要高得多 支持范围查询 B 树能够支持范围查询 这在 MySQL 中经常用于 WHERE 子句中的 BETWE
  • HC-05蓝牙模块使用记录

    前言 后面可能需要用到蓝牙远程控制 所以提前了解了一下 主要是用买来的蓝牙模块HC 05 主要包括一个蓝牙芯片CSR BC417 该公司是剑桥的一个公司 现已被高通收购 和一个FLASH芯片 调试一下两个HC 05之间基本的通讯以及与手机蓝
  • 关于TypeScript的引用类型

    基本数据类型 引用数据类型 赋值引用 public copyCite let obj name 1 let copyObj obj obj name 2 console log copyObj name 2 由于对象之间的赋值是复制了地址
  • 位运算的应用

    前天几天研究了下JDK的Collection接口 本来准备接着研究Map接口 可是一查看HashMap类源码傻眼咯 到处是位运算实现 所以我觉得还是有必要先补补位运算知识 不然代码看起来有点费力 今天系统研究了下 现记录如下 首先要明白一个
  • elementUI的el-table表格不生效问题

    我之前下载的elementUI依赖是用的镜像cnpm 删掉原来的依赖重新下npm的依赖npm i element ui S 重启前台服务就可以了
  • vue3和vite

    1 安装 vue cli 3 yarn add vue cli next 2 安装vite vue add vite 3 安装成功后package json中会添加 scripts vite node bin vite devDepende
  • 【hello C++】智能指针

    目录 一 内存泄漏 1 1 什么是内存泄漏 内存泄漏的危害 1 2 内存泄漏分类 1 3 如何检测内存泄漏 1 4 如何避免内存泄漏 二 智能指针的使用及原理 2 1 RAII 2 2 智能指针的原理 2 3 智能指针的发展历程 2 4 智
  • componentDidUpdate vs componentWillReceiveProps

    componentDidUpdate有两个参数prevProps和prevState 不管是父组件props的修改还是state状态的更改都会触发该方法 而componentWillReceiveProps只有在父组件重新render pr
  • IDEA 2020.1官网汉化插件安装

    idea 终于更新了2020 1版本 推荐使用2020的版本 新增了好多的特性 官方也终于支持了中文语言包 但是有些兄弟下载后在插件市场无法找到官方的汉化包等问题 请安装下面操作即可 1 去IDEA插件中心 https plugins je
  • protobuf通信消息设计技巧备忘

    1 有一个全局的ProtobufMessage 所有的requestXXX responseXXX都作为他的一个可选属性 这样简单粗暴的避免了需要二次序列化反序列化的恶心问题 2 有一个CommonMessage作为他的一个字段 用来存放公
  • Data-centric Artificial Intelligence: A Survey

    本文是AI相关的论文 针对 Data centric Artificial Intelligence A Survey 的翻译 以数据为中心的人工智能 综述 摘要 1 引言 2 数据为中心AI的背景 3 训练数据开发 4 推理数据开发 5
  • 逻辑地址空间、页表与如何确定页表项大小

    32位逻辑地址空间 一页4KB 按字节编制 页式内存管理中如何确定页表项大小 因为是32位逻辑地址 故寻址空间为2 32B 而一页大小为4KB 故需要2 32 4B 2 20页 1M页 假设在内存中地址 而页表则是对这些页表的记录 因一页大
  • lastpass 右边_如何使用LastPass的替代产品Bitwarden管理密码

    lastpass 右边 您是否觉得自己拥有的密码超出了跟踪范围 这可能不仅仅是一种感觉 像我们大多数人一样 您可能很难记住所有这些密码 无论它们多么简单或复杂 许多人使用诸如LastPass和1Password之类的流行服务来帮助他们弄乱密
  • ARMv7体系结构汇总

    文章目录 1 处理器工作模式 2 处理器工作状态 3 ARM寄存器 3 1 通用寄存器 3 2 状态寄存器 3 3 备份的程序状态寄存器SPSR 3 4 Thumb寄存器 4 ARM指令系统 4 1 指令和指令格式 4 2 指令的可选后缀