文章目录
ARM体系结构与编程
ARM7(ARMV4)和ARM9之后的指令操作流程
ARM7(ARMV4)三级指令流水线
三级流水线
**PC**
ARM7三级流水线特例——ldr指令
ARM7三级流水线特例——bl指令
ARM7三级流水线特例——中断
ARM9(ARMV4)以后的ARM核的五级指令流水线
ARM编程模型
ARM核的七种工作模式
ARM核的两种工作状态
ARM核的37个寄存器
ARM支持的数据类型
ARM支持大端和小端模式,默认小端模式
ARM汇编语法格式:
ARM异常
ARM一旦触发异常会如何处理
ARM核跳转的方式
ARM指令——分支跳转指令
ARM体系结构与编程
当前ARM核的版本划分,
- ARMV4:这其中包含的小版本有:
- ARM720T
- ARM920T
- ARMV5:
- Xscale
- ARM10
- ARMV6:
- ARM11
- ARMV7:
- ARM-CORTEX-A8
- ARM-CORTEX-A9
- ARM-CORTEX-A15
- ARM-CORTEX-M3/M0 STM32(M3)主打控制处理
- ARMV8:(正式支持64位)
- ARM-CORTEX-A53
- ARM-CORTEX-A57
ARM7(ARMV4)和ARM9之后的指令操作流程
ARM7使用的是三级指令流水线,但是ARM9和ARM9之后的版本都使用五级指令流水线。其中需要说明:
- 指令:给CPU核下发的命令,CPU核根据命令完成一个功能。(例如:给CPU核发一个add指令,就是告诉CPU核做数据的加法运算)
- 指令在哪里呢:指令就是存在于二进制可执行文件中,CPU核要想执行指令,首先将指令对应的二进制文件加载到内存中,指令最终存在于内存中,内存的访问以地址的执行访问,所以每一条指令也有对应的内存存储地址,当CPU要想运行一条指令,首先从内存中获取到指令。
- 注意: CPU核工作在ARM状态下:一条指令的宽度为32位(4字节);CPU核工作在THUMB状态下:一条指令的宽度为16位(2字节)。
ARM7(ARMV4)三级指令流水线
三级流水线
- 取指:CPU核中的取指器(硬件)从内存中读取要运行的指令。
- 解码:CPU核取完指令后,该指令还不能直接运行(CPU核不识别),需要使用解码器进行解码成机器码。
- 执行:解码完成后,CPU核最终执行指令。
- 总结: 取指(F)->解码(D)->执行(E)
PC
- PC是个寄存器,位宽为32位。它是ARM核(CPU核)中的寄存器,用来保存取指器要取的那条指令对应的内存存储地址。
例如:
#内存存储地址 指令 0x48000000 add 0x48000004 sub 0x48000008 and ....
当上述add指令呗执行的时候,取指器取得and指令,所以此时PC=0x48000008。
ARM7三级流水线特例——ldr指令
ldr指令功能:CPU核利用此指令能够从外设中加载数据到CPU核中。
ldr指令流水线分为五级:
取指(F)->解码(D)->执行(E)->访存(M)->写回(W)
说明:
- 访存:CPU核寻找外设地址。
- 写回:CPU核一旦找到了外设地址,将外设的数据加载到CPU核中。
- 注意:ARM7的ldr指令在M和W的时候,跟在其后的两条指令的处理需要延后两个指令周期。
ARM7三级流水线特例——bl指令
bl指令的功能:CPU核执行bl指令,能够跳转到bl指令指定的内存位置去运行(取指->解码->执行)。
bl指令处理流水线需要五级:
取指(F)->解码(D)->执行(E)->保存返回地址(L)->正式跳转(A)
说明:
- 保存返回地址(L):CPU核跳转到bl指令指定的地址运行之前先把返回地址(bl治疗的下一条指令)进行保存处理。
- 正式跳转(A):CPU核跑到bl执行指定的地址去运行。
ARM7三级流水线特例——中断
中断定义:中断是计算机非常重要的机制
问:计算机中为什么有中断呢?
- 中断产生的根本原因就是CPU的数据除了速度远远快于外设的数据处理速度。举个例子:以CPU核读取UART接收缓冲区的数据为例,当CPU核发现UART接收缓冲区没有数据,通常的操作都是轮询方式(死等),判断接收缓冲区有没有数据到来,但是这种放松会大大消耗CPU的利用率,此时此刻就需要用到中断方式操作UART接收缓冲区。当接收缓冲区有数据,UART控制器会给CPU发送一个中断信号告诉CPU有数据到来,CPU就会停止手上的工作转而去处理UART接收数据,之后在回到之前的流程中继续处理刚刚的事情。这样大大提高了CPU的利用率。
CPU核接收到中断信号后,开始处理中断,中断处理流水线需要四级:
切记: 当CPU核正在执行某个处理时,CPU核受到中断信号,CPU核处理中断一定是在当前处理执行完之后再去处理。
解码中断(DI)->执行中断(EI)->保存返回地址(L)->正式跳转(A)
说明:
- 保存返回地址:中断产生之前,CPU在执行别的指令,当中断到来,CPU核转而执行中断处理函数,处理完还需要再回来继续处理之前的指令,所以需要保存返回地址。
ARM9(ARMV4)以后的ARM核的五级指令流水线
ARM9以后的所有ARM核指令流水线一律采用五级流水线,也就是将访存(M)和写回(W)给每一条指令都添加上。
- F->D->E->M->W
ARM编程模型
ARM核的七种工作模式
- SVC管理模式: 当系统复位或者软件执行swi指令,CPU核切换到此模式下。
- FIQ快速中断模式: 外设给CPU核发送一个FIQ快速中断信号,CPU核会切换到此模式下。
- IRQ中断模式: 外设给CPU核发送一个IRQ普通中断信号,CPU核切换到此模式。
- Abort中止模式: 当CPU核取指失败或者访存失败,CPU核进入此模式。
- undef未定义指令模式: 当CPU核执行一个不认识的指令(lisi),CPU核进入此模式。
- system系统模式:
- user用户模式: system和user一样,CPU核正常运行情况下,CPU就会处于这两个模式其中之一。Linux系统下,当CPU处理一个进程时就工作在user模式下。
ARM核的两种工作状态
ARM状态:
- ARM指令:位宽 32 位。
- Thumb状态:
- thumb指令:位宽 16 位。
ARM核的37个寄存器
- 寄存器:暂存数据的硬件,类似内存
- 寄存器分类:特殊功能寄存器和ARM寄存器。
- 特殊功能寄存器:各种硬件控制器内核的寄存器,也就是之前说的CPU通过访问这样一类寄存器都是通过地址指针形式访问。
- ARM寄存器:仅仅存在于ARM核内部,CPU核访问内部的ARM寄存器通过名字(不论大小写),总共37个ARM寄存器。
ARM核37个寄存器:
- 31个通用寄存器:r0, r1, r2, … … r15,每一种工作模式下又有自己独立的寄存器。
- r15又称gc:永远只保存取指器要取的那条指令的内存存储地址。
- r14又称lr:永远只保存返回地址。
- r13又称sp:永远只保存栈指针。
6个状态寄存器:
- 1个cpsr和5个spsr
- cpsr:又称当前程序状态寄存器,也就是保存当前程序运行状态。
- spsr:又称备份程序状态寄存器,本质目的就是为了保存cpsr的值。
详解CPSR程序状态寄存器:
- BIT[4:0]:模式位mode
- 10000 ,表示当前CPU核处于用户模式。
- 10011 ,表示当前CPU核处于SVC管理模式。
- BIT[5]:状态位T
- 0 - ARM核处于ARM状态
- 1 - ARM核处于thumb状态
- BIT[6]:FIQ配置位F
- 0 - 使能FIQ中断功能
- 1 - 禁止FIQ中断功能
- BIT[7]:IRQ配置位T
- 0 - 使能IRQ中断功能
- 1 - 禁止IRQ中断功能
- BIT[28]:溢出标志位V
- 0 - 表示程序运行结果没有发送溢出。
- 1 - 表示程序运算结果发送溢出
- BIT[29]:进位或者借位表示C
- 0 - 表示程序运算没有发送进位或者借位。
- 1 - 表示程序运算时发送了进位或者借位。
- BIT[30]:零位Z
- 0 - 表示程序运算结果为非0
- 1 - 表示程序运算结果为0
- BIT[31]:负或者小于位N
- 0 - 表示程序运算结果不为负数或者不小于
- 1 - 表示程序运算结果为负数或者小于
- BIT[31:28]简称NZCV,只要程序运行,CPSR的值会随时随刻发生改变。
注意:
- 现在有一个进程获取到CPU资源,此进程就可以投入运行,此时对应的CPU核的工作模式为User用户模式,此时由于CPU核执行进程对应的代码cpsr时刻进行改变,突然UART控制器给CPU核发送一个IRQ中断电信号,此时CPU核就会由 User用户模式切换到IRQ普通中断模式,紧接着CPU核开始去处理IRQ中断,本质就是CPU核去执行这个IRQ中断对应的一个函数而已,此函数也是一个程序,如果此程序运行,将来势必也会影响cpsr,但是将来中断处理完毕CPU核还要返回到原先被打断的进程继续运行,为了让原先的进程能够继续正确运行,所以CPU核在处理中断之前,先把当前进程的cpsr的值备份到IRQ模式下的spsr,将来中断返回 只需从IRQ模式下的spsr恢复原先进程的cpsr。
ARM支持的数据类型
Byte:1字节
HalfWord:2字节
Word:4字节
DoubleWord:8字节
ARM支持大端和小端模式,默认小端模式
X86是小端,PowerPC是大端。
ARM汇编语法格式:
参考代码:
.text @代码段的起始 .code 32 @使用ARM指令 .global start @声明一个全局标签start start: @全局标签的内容如下 mov r0, #10 @r0=10 ldr r1, =3 @r1=3 add r0, r0, r1@r0=r0+r1 b . @while(1); .end @代码段的结束
切记:影响CPSR的NZCV位的两种情形:
- 1.指令后面加s,运算结果影响CPSR的NZCV
add r0, r0, r1 #@r0=1,r1=-1 #@r0保存运算结果,不影响CPSR的NZCV adds r0, r0, r1 #@r0=1,r1=-1 @CPSR的Z=1
- 2.cmp比较指令后面不加s,运算结果同样影响cpsr
cmp比较指令本质做减法运算
cmp r0, r1 #@本质:运算结果=r0-r1
ARM异常
ARM核有7种异常:
异常 工作模式 CPU核运行地址 场景
复位异常 SVC管理模式 0x00 系统复位
undef未定义指令异常 undef未定义指令模式 0x04 CPU核执行一个不认识的指令
软中断异常 SVC管理模式 0x08 CPU核执行swi指令
预取指令异常 abort中止模式 0x0C CPU核取指失败
数据处理异常 abort中止模式 0x10 CPU核访存失败
IRQ中断异常 IRQ中断模式 0x18 外设给CPU发送IRQ中断电信号
FIQ中断异常 FIQ快速中断模式 0x1C 外设给CPU核发送FIQ快速中断电信号异常
- 注意:一旦异常发生,CPU核会毫无条件的必须强制跑到对应的入口地址去执行。
ARM一旦触发异常会如何处理
以UART控制器给CPU核发送IRQ中断电信号为例,
理清IRQ异常的处理流程:
- 1.当UART控制器准备好数据以后,首先会给中断控制器发送一个中断电信号。
- 2.中断控制器接收到这个中断电信号以后经过一番的判断之后,中断控制器最终以IRQ的形式给CPU核发送一个IRQ中断电信号。
- 3.CPU核一旦接收到IRQ中断电信号,就会触发一个IRQ异常,CPU核立马要处理这个IRQ异常。
CPU核硬件上自动完成以下工作:
- 1.把当前程序对应的cpsr的值保存到IRQ中断模式下的spsr_irq
- 2.设置cpsr,将cpsr的:
- bit[4:0]=IRQ工作模式对应的值,让CPU核
- 切换到IRQ中断模式
- bit[5]=0,让ARM核切换到ARM状态下
- bit[7:6]=11,禁止ARM核响应IRQ和FIQ中断
- 3.保存返回地址:lr=pc-4
- 问:为什么是lr=pc-4呢?
- 答:例如:
- 内存地址 指令
- 0x8000 add
- 0x8004 sub
- 0x8008 orr
- 当add指令执行的时候:pc=0x8008
- 当add指令执行的时候,触发IRQ异常
- 将来IRQ异常处理完毕,CPU核返回到0x8004
- 去运行,所以lr=pc-4=0x8008-4=0x8004
- 4.设置pc=0x18
- 问:为什么0x18呢?
- 答:因为IRQ异常处理的入口地址为0x18
- 问:pc=0x18代表什么含义呢?
- 答:本质就是让CPU核跑到0x18地址去运行(F->D->E->M->W)。
- 问:0x18地址放什么东西?
- 答:0x18势必放自己编写的软件代码
切记:只要给pc赋值(地址),那么CPU核就会跑到对应的地址去运行。
- 结论:一旦ARM核做pc=0x18,让CPU核跑到0x18地址去运行,至此正式开启了软件进一步处理IRQ异常的流程。
软件处理IRQ异常的流程:
- 软件如何处理IRQ异常完全有程序员自行决定,软件处理IRQ异常结束以后,最后让CPU核返回到原先被打断的地方(某个程序)继续执行,软件只需完成以下两个动作即可
- 实现返回:
- cpsr=spsr_irq:将IRQ模式下的spsr的值归还给cpsr,spsr_irq保存原先被打断的程序运行的状态。
- pc=lr:lr保存的返回地址,让CPU核跑到原先被打断的地方继续执行
- 至此:IRQ异常处理完毕!
ARM核跳转的方式
ARM核跳转的方式有三种:
- ARM核发生异常,一旦发生异常,ARM核跑到对应的异常入口地址去。
- ARM核执行b或者bl跳转指令。
- 直接向pc赋值(此方法最直接)
ARM指令——分支跳转指令
ARM指令集之分支跳转指令:b/bl/bx
b为不带返回的跳转指令
- 跳转范围相对PC,±32MB
b loop 无条件跳转
beq loop 有条件跳转
bl为待返回的跳转指令
- 跳转范围相对PC,±32MB
切记:当CPU核执行bl指令时,CPU核硬件上自动将
下一条指令的地址保存在lr中
所以将来软件返回的指令为:mov pc, lr
例如:
内存地址 指令
0x8000 bl strcmp @当bl执行时,pc=0x8008,lr=0x8004
0x8004 add r0, r0, r1
0x8008 sub r0, r0, r1
strcmp:
一大堆指令
mov pc, lr @pc=lr=0x8004,让CPU核跑到0x8004去运行
bx带状态切换的指令(了解)
- bx跳转的地址的bit[0]=0:切换到ARM状态
bx跳转的地址的bit[0]=1:切换到Thumb状态
例如:
ldr r0, =0x48000000
bx r0 @让CPU核切换到ARM状态并且跳转到0x48000000去运行
ldr r0, =0x48000001
bx r0 @让CPU核切换到Thumb状态并且跳转到0x48000001去运行