一、ARM架构

ARM芯片属于精简指令集计算机(RISC:Reduced Instruction Set Computing),它所用的指令比较简单,有如下特点:

  • 对内存只有读、写指令
  • 对于数据的运算是在CPU内部实现
  • 使用RISC指令的CPU复杂度小一点,易于设计

比如对于a=a+b这样的算式,需要经过下面4个步骤才可以实现:

细看这几个步骤,有些疑问:

  • 读a,那么a的值读出来后保存在CPU里面哪里?
  • 读b,那么b的值读出来后保存在CPU里面哪里?
  • a+b的结果又保存在哪里?

我们需要深入ARM处理器的内部。简单概括如下,我们先忽略各种CPU模式(系统模式、用户模式等等)。

算术逻辑单元(Arithmetic&logical Unit)是中央处理器(CPU)的执行单元,是所有中央处理器的核心组成部分。


CPU运行时,先去Flash上取得指令,再执行指令:

  • 把内存a的值读入CPU寄存器R0
  • 把内存b的值读入CPU寄存器R1
  • 把R0、R1累加,存入R0
  • 把R0的值写入内存a

怎么理解Flash上的指令?看下一节。


一个片上系统的最小组成部分如下:


二、 汇编指令

当前只介绍5条汇编指令:

  • 读内存:Load,LDR
  • 写内存:Store,STR
  • 加减法:ADD, SUB
  • 入栈:PUSH,实质上就是写内存STR
  • 出栈:POP,实质上就是读内存LDR
  • 跳转:BL,即 Branch And Link


其他知识:

  • CPU内部有 R0、R1、……、R15 共16个寄存器
  • 某些寄存器有特殊作用
    • R13,别名SP,栈寄存器,保存着栈的地址
    • R14,别名LR,返回地址,保存着函数的返回地址
    • R15,别名PC,程序计数器,也就是当期程序运行到哪了


要读内存:读内存哪个地址?读到的数据保存在哪里?读多少字节?

  • LDR R0, [R1, #0x00]
    • 源地址:R1+0x00,注意:不是读R1,是把R1的值当做内存的地址
    • 目的:R0,CPU的寄存器
    • 长度:4字节,LDR指令就是读4字节,LDRH是读2字节,LDRB是读1字节


要写内存:写内存哪个地址?从哪里得到数据?写多少字节?

  • STR R0, [R1, #0x00]
    • 目的地址:R1+0x00,注意:不是写R1,是把R1的值当做内存的地址
    • 源:R0,CPU的寄存器
    • 长度:4字节,STR指令就是读4字节,STRH是读2字节,STRB是读1字节

加减法指令,不涉及内存操作,只在 CPU 寄存器上操作。


入栈:把CPU的寄存器的值,写到内存上

  • PUSH {R3, LR}

    • 源:CPU的寄存器R3、LR的值
    • 目的:内存,内存哪里?使用CPU的 SP(stack pointer)寄存器指定内存地址
    • 长度:大括号里所有寄存器的数据长度,每个寄存器4字节
    • 注意:低编号的寄存器,保存在内存的低地址处 ,即:高标号寄存器写入高地址的栈里,低标号寄存器写入低地址的栈里
    • 执行结果如下


出栈:把内存中的数值,写到CPU的寄存器

  • POP {R3, PC}
    • 源:内存,内存哪里?使用CPU的 SP(stack pointer)寄存器指定内存地址

    • 目的:CPU的寄存器R3、PC的值

    • 长度:大括号里所有寄存器的数据长度,每个寄存器4字节

    • 注意:内存的低地址处的数据,写到CPU低编号的寄存器,即:高标号寄存器的内容来自高地址的栈,低标号寄存器的内容来自低地址的栈

    • 执行结果如下


LR(R14)寄存器

  • 子程序的返回地址:从子程序返回后,主程序继续执行的指令的地址称为子程序的返回地址
  • LR也叫链接寄存器,用于存放子程序的返回地址。在要进入子程序之前,先将子程序的返回地址存入LR