一、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