1、ARM指令(注意!并不包含Thumb指令)

指令分类: 分支指令、数据处理指令、程序状态寄存器(CPSR)处理指令、加载/存储指令、协处理器指令、异常产生指令六大类。
下表为基本ARM指令,不包括派生的ARM指令:
17--嵌入式基础之ARM汇编 - 图1
17--嵌入式基础之ARM汇编 - 图2
17--嵌入式基础之ARM汇编 - 图3

2、ARM指令格式:

  1. <opcode> {condition} {S} {Rd}, Operand1, Operand2
  2. -----------------------------------------------------------------------
  3. <opcode> //操作码。如ADD表示算术加操作指令
  4. {condition} //条件码。决定指令执行的条件(可省略)
  5. {S} //指令执行时是否更新CPRS寄存器的值(可省略)
  6. 必须有空格
  7. {Rd} //目的寄存器。存储指令计算结果
  8. Operand1 //第一个操作数。可以是一个寄存器或一个立即数
  9. Operand2 //第二个(可变)操作数
  10. • 1
  11. • 2
  12. • 3
  13. • 4
  14. • 5
  15. • 6
  16. • 7
  17. • 8
  18. • 9

条件码:

17--嵌入式基础之ARM汇编 - 图4

3、ARM指令中的移位操作符

对通用寄存器进行移位操作的格式如下:

Rm, <opsh>#<shift>
--------------------------------------------------
其中,Rm为要移位的通用寄存器;<opsh>为移位操作符,如下表;<shift>为移位次数,移位次数为0-31。
• 1
• 2
• 3

17--嵌入式基础之ARM汇编 - 图5

4、ARM指令的寻址方式

立即寻址: 操作数本身包含在指令中

MOV R0, #1314              //后面是立即数(常数)以#号作为前缀
• 1

寄存器寻址: 寄存器中的数值作为操作数

MOV R0, R1                 //都为寄存器
ADD R0,R1,R2               //R0 = R1+R2
• 1
• 2

寄存器间接寻址: 寄存器中的值作为地址,再通过这个地址去取得操作数

LDR R0, [R1]               //后面是地址指针,在中括号中
• 1

基址变址寻址: 将寄存器中的值与指令中给出的地址偏移量相加,从而得到一个新的地址,再通过这个地址去取得操作数

LDR R0, [R1, #-4]          //后面是地址指针,中括号中为立即寻址
• 1

多寄存器寻址: 可以一次完成最多16个寄存器值的传送。

LDMIA R0, {R1,R2,R3 }      //R1 <- [R0]; R2 <- [R0+4]; R3 <- [R0+8];
• 1

相对寻址: 在寄存器寻址得到操作数后再进行移位操作,得到最终的操作数

MOV R0,R2,LSL #3           //R2左移3位,结果赋给R0
• 1

堆栈寻址: 先进后出方式,使用堆栈指针指示当前操作位置,堆栈指针总是指向栈顶
四种类型的堆栈工作方式:
满递增堆栈:堆栈指针指向最后压入的数据,且由低地址向高地址生成
满递减堆栈:堆栈指针指向最后压入的数据,且由高地址向低地址生成
空递增堆栈:堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成
空递减堆栈:堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成

STMFD SP!, {R1-R7, LR}     //将R1-R7,LR压入堆栈。满递减堆栈 
• 1

5、ARM处理器支持的伪指令

指令 说明
ADR 用于相对偏移地址加载到通用寄存器中
LDR 用于一个32位常数的加载或地址的加载
NOP 产生空操作,用于简单延时

6、汇编程序设计

顺序程序设计

START LDR R0,=0x12345678        ;R0=0x12345678
      LDR R1,=0x30100000        ;R1=0x30100000
      LDR R2,=0x87654321        ;R2=0x87654321
      STR R2,[R1]               ;把R2中的数据写入R1指示的内存单元0x30100000中
      LDR R3,[R1]               ;取R1指示区域的数据到R3,即数据0x87654321
      AND R3,R3,#0x000000FF     ;R3的值与0x87654321与0x000000FF相与后得到R3=0x00000021
      ADD R0,R0,R3,LSL #2       ;将R3左移2位后得到0x00000084,与R0相加结果返回R0,因此R0=0x123456FC
      STR R0,[R1]               ;R0中的值存入0x00100000开始的区域
      END
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9

分支程序设计

CMPA  LDR R0,=0X30007000        ;指向首地址
      LDR R1,[R0]               ;取第一个数a
      LDR R2,[R0+4]             ;取第二个数b
      CMP R1,R2                 ;第一个数与第二个数比较
      BHI NEXT1                 ;a大于等于b,则跳转
      STR R2,[R0]               ;a,b交换
      STR R1,[R0+4]             ;a,b交换
NEXT1 LDR R1,[R0+4]             ;取中间的数
      LDR R2,[R0+8]             ;取第三个数
      CMP R1,R2                 ;b大于等于c
      BHI NEXT2
      STR R2,[R0+4]             ;b,c交换
      STR R1,[R0+8]             ;b,c交换
NEXT2 ……
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14

循环程序设计
计算1-200的整数累加之和,并将结果存入字变量SUM中

SUM   DCD 0                     ;定义32位字变量SUM并赋值为0
      ENTRY
      CODE32                    ;32位ARM模式代码
LOOPS LDR R0,=200               ;循环次数
      MOV R1,#0                 ;累加和清楚
LOPPA ADD R1,R1,R0              ;累加操作和在R1中
      SUBS R0,R0,#1             ;计数减1,产生标志进CPSR
      BCC LOPPA                 ;不满200继续循环
      LDR R0,=SUM               ;变量指针指向R0
      STR R1,[R0]               ;结果存入SUM中
      END
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11

7、嵌入式C语言与汇编语言混编

实际应用中,关键底层的初始化部分和驱动使用汇编语言,主要的编程任务一般使用C语言完成。
在C语言中嵌入汇编语言的语法格式:

__ASM                           //注意,是双下划线
{
    汇编指令序列;
}
• 1
• 2
• 3
• 4

代码实例:

void Enable_disable_IRQ(int Selector)
{
    int tmp;
    if (Selector == 0)
    {
        /*嵌入关中断汇编程序*/
        __asm                        //双下划线
        {
            MRS tmp,CPSR             ;读CPSR状态寄存器的值到tmp
            ORR tmp,tmp,#0x80        ;置位b7(I)以关中断
            MSR CPSR_C,tmp           ;写入CPSR寄存器C域中,以正式关中断
        }
    }
    else
    {
        /*嵌入开中断汇编程序*/
        __asm                        //双下划线
        {
            MRS tmp,CPSR             ;读CPSR状态寄存器的值到tmp
            BIC tmp,tmp,#0x80        ;清b7(I)以开中断
            MSR CPSR_C,tmp           ;写入CPSR寄存器C域中,以正式开中断
        }
    }
}
main()
{
    Enable_disable_IRQ(0)            ;关中断
    ……                               ;初始化操作
    Enable_disable_IRQ(1)            ;开中断
    while(1)
    {
        ……                           ;循环主体
    }
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34