LV08-01-ARM体系-02-ARM基础知识
本文主要是ARM基础知识——ARM的存储模型、工作模式、寄存器与异常等基础知识相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows | windows11 |
Ubuntu | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
SecureCRT | Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日 |
开发板 | 正点原子 i.MX6ULL Linux阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
STM32开发板 | 正点原子战舰V3(STM32F103ZET6) |
Keil(MDK) | Keil uVision V4.54.0.0 |
点击查看本文参考资料
参考方向 | 参考原文 |
--- | --- |
一、ARM
存储模型
1. 数据类型
ARM
采用32
位架构,基本数据类型有以下三种:
Byte | 8bits |
Halfword | 16bits |
Word | 32bits |
2. 数据存储
Word
型数据在内存的起始地址必须是4
的整数倍。Halfword
型数据在内存的起始地址必须是2
的整数倍。即数据本身是多少位在内存存储时就应该多少位对齐。
3. 关于字节序
字节序在前边其实已经接触过了,主要分为两种:
大端对齐 | 低地址存放高位,高地址存放低位 |
小端对齐 | 低地址存放低位,高地址存放高位 |
【注意】在ARM
中,一般使用小端对齐。
例如,以a = 0x12345678
为例,
- 大端对齐
地址 | 数据 |
N+0 | 0x12 |
N+1 | 0x34 |
N+2 | 0x56 |
N+3 | 0x78 |
- 小端对齐
地址 | 数据 |
N+0 | 0x78 |
N+1 | 0x56 |
N+2 | 0x34 |
N+3 | 0x12 |
4. 指令存储
处理器处于ARM
状态时,所有指令在内存的起始地址必须是4
的整数倍。程序计数器PC
值由其[31:2]
决定,[1:0]
位未定义。处理器处于Thumb
状态时,所有指令在内存的起始地址必须是2
的整数倍。程序计数器PC
值由其[31:1]
决定,[0]
位未定义。
总的来说就是指令本身是多少位在内存存储时就应该多少位对齐。
二、ARM
工作模式
以前的 ARM
处理器有 7
种运行模型: User
、 FIQ
、 IRQ
、 Supervisor(SVC)
、 Abort
、 Undef
和 System
,其中 User
是非特权模式,其余 6
种都是特权模式。但新的 Cortex-A
架构加入了TrustZone
安全扩展,所以就新加了一种运行模式: Monitor
,新的处理器架构还支持虚拟化扩展,因此又加入了另一个运行模式: Hyp
,所以 Cortex-A
系列的处理器最多可以有9
种模式:
user | 用户模式,大部分程序运行时候的非特权模式,一般在执行上层的应用程序时ARM处于该模式。 |
FIQ | 快速中断模式,进入FIQ中断异常,当一个高优先级中断产生后ARM将进入这种模式。 |
IRQ | 一般中断模式,当一个低优先级中断产生后ARM将进入这种模式。 |
Supervisor(SVC) | 超级管理员,它主要是用来管理调用指令被执行或者reset的时候,当复位或执行软中断指令后ARM将进入这种模式。 |
Monitor(MON) | 监视模式,为了安全而扩展出的用于执行安全监控代码的模式。 |
Abort(ABT) | 数据访问终止模式,当产生存取异常时ARM将进入这种模式。 |
Hyp(HYP) | 是一个超级的监视者的模式,它比超级管理员要稍微低一点,它主要是用来做一些虚拟化的扩展。 |
Undef(UND) | 它就是未定义的指令执行的时候,比如说一条指令是CPU不识别的,就叫做未定义, 当执行这种未定义的指令时ARM将进入这种模式。 |
System(SYS) | 系统模式,当系统自己异常的时候,就会发生这样的模式,它有一个特点就是可以进行各个模式的切换,在不同的状态的时候,访问的寄存器就有可能不一样,这个模式用到的寄存器与用户模式是共享的,只是访问级别不一样。 |
上边的所有工作模式中,除了 User
也就是用户模式以外,其它8
种运行模式都是特权模式。这几个运行模式可以通过软件进行任意切换,也可以通过中断或者异常来进行切换。
大多数的程序都运行在用户模式,用户模式下是不能访问系统所有资源的,有些资源是受限的,要想访问这些受限的资源就必须进行模式切换。但是用户模式是不能直接进行切换的,用户模式下需要借助异常来完成模式切换,当要切换模式的时候,应用程序可以产生异常,在异常的处理过程中完成处理器模式切换。
当中断或者异常发生以后,处理器就会进入到相应的异常模式种,每一种模式都有一组寄存器供异常处理程序使用,这样的目的是为了保证在进入异常 模式以后,用户模式下的寄存器不会被破坏。
三、ARM
寄存器组织
1. 寄存器的概念
寄存器是处理器内部的存储器,是没有地址的。它一般用于暂时存放参与运算的数据和运算结果, 包括通用寄存器、专用寄存器、控制寄存器。
2. ARM
寄存器
ARM
架构提供了 16
个 32
位的通用寄存器 (R0~R15
)供软件使用,前 15
个 (R0~R14
)可以用作通用的数据存储, R15
是程序计数器 PC(Program Counter)
,用于存储当前取址指令的地址。另外 ARM
还提供了一个当前程序状态寄存器 CPSR
和一个备份程序状态寄存器 SPSR
, SPSR
寄存器就是 CPSR
寄存器的备份。
3. 不同模式下的寄存器组
在上边介绍的寄存器中,有些是所有模式所共用的同一个物理寄存器,有一些是各模式自己所独立拥有的,各个模式所拥有的寄存器如下表:
User | SYS | FIQ | IRQ | ABT | SVC | UND | MON | HYP |
R0 | R0 | R0 | R0 | R0 | R0 | R0 | R0 | R0 |
R1 | R1 | R1 | R1 | R1 | R1 | R1 | R1 | R1 |
R2 | R2 | R2 | R2 | R2 | R2 | R2 | R2 | R2 |
R3 | R3 | R3 | R3 | R3 | R3 | R3 | R3 | R3 |
R4 | R4 | R4 | R4 | R4 | R4 | R4 | R4 | R4 |
R5 | R5 | R5 | R5 | R5 | R5 | R5 | R5 | R5 |
R6 | R6 | R6 | R6 | R6 | R6 | R6 | R6 | R6 |
R7 | R7 | R7 | R7 | R7 | R7 | R7 | R7 | R7 |
R8 | R8 | R8_fiq | R8 | R8 | R8 | R8 | R8 | R8 |
R9 | R9 | R9_fiq | R9 | R9 | R9 | R9 | R9 | R9 |
R10 | R10 | R10_fiq | R10 | R10 | R10 | R10 | R10 | R10 |
R11 | R11 | R11_fiq | R11 | R11 | R11 | R11 | R11 | R11 |
R12 | R12 | R12_fiq | R12 | R12 | R12 | R12 | R12 | R12 |
R13(SP) | R13(SP) | SP_fiq | SP_irq | SP_abt | SP_svc | SP_und | SP_mon | SP_hyp |
R14(LR) | R14(LR) | LR_fiq | LR_irq | LR_abt | LR_svc | LR_und | LR_mon | R14(LR) |
R15(PC) | R15(PC) | R15(PC) | R15(PC) | R15(PC) | R15(PC) | R15(PC) | R15(PC) | R15(PC) |
CPSR | CPSR | CPSR | CPSR | CPSR | CPSR | CPSR | CPSR | CPSR |
- | - | SPSR_fiq | SPSR_irq | SPSR_abt | SPSR_svc | SPSR_und | SPSR_mon | SPSR_hyp |
- | - | - | - | - | - | - | - | ELR_hyp |
4. 专用寄存器说明
4.1 R13(SP,Stack Pointer)
栈指针,用于存储当前模式下的栈顶地址。
4.2 R14(LR,Link Register)
链接寄存器,一般有以下两种用途:
(1)执行跳转指令(BL/BLX
)时,LR
会自动保存跳转指令下一条指令的地址,当程序需要返回时将LR
的值复制到PC
即可实现程序返回。
(2)产生异常时,对应异常模式下的LR
会自动保存被异常打断的指令的下一条指令的地址,异常处理结束后将LR
的值复制到PC
可实现程序返回。
当执行跳转指令或产生异常时,LR
寄存器中不会凭空产生一个返回地址其原理是当执行跳转指令或产生异常时,处理器内部会将PC
寄存器中的值拷贝到LR
寄存器中,然后再将LR
寄存器中的值自减4
。
点击查看 LR 在 BL 和 IRQ 中断的不同
- BL
当执行BL
指令时,指令执行过程中处理器内部就会将PC
寄存器的值拷贝到LR
寄存器,然后再将LR
寄存器中的值自减4
, 所以LR
寄存器中保存的就是BL
指令下一条指令的地址。
- IRQ中断
当正在执行一条指令时产生了一个IRQ
中断,执行这条指令过程中处理器不会保存返回地址,而是执行完成后才会保存PC
寄存器中的值到LR
寄存器,但发生IRQ
时正在执行的指令在执行完成后PC
的值又会自动增4
,所以对于IRQ
来说LR
中保存的是被中断打断的指令的下下条指令的地址。所以我们在写中断处理的时候要注意修正这个问题,否则就会少一条指令。
另外R14
也可以作为普通寄存器使用。
4.3 R15(PC,Program Counter)
程序计数器,用于存储当前取址指令的地址。对于三级流水线的ARM
处理器来说,R15
保存着当前执行的指令地址值加8
个字节,这是因为ARM
的流水线机制导致的。ARM
处理器的3
级流水线为:取指→译码→执行,这三级流水线循环执行,比如当前正在执行第一条指令的同时也对第二条指令进行译码,第三条指令也同时被取出存放在R15(PC)
中。
我们以当前正在执行的指令作为参考点的话,也就是以第一条指令为参考点,此时R15(PC)
中存放的就是第三条指令,换句话说就是R15(PC)
总是指向当前正在执行的指令地址再加上2
条指令的地址。对于32
位的 ARM
处理器,每条指令是 4
个字节,所以有:
1 | R15 (PC)值 = 当前执行的程序位置 + 8 个字节 |
5. CPSR
和SPSR
所有的处理器模式都共用一个CPSR
物理寄存器,因此CPSR
可以在任何模式下被访问。CPSR
是当前程序状态寄存器,该寄存器包含了条件标志位、中断禁止位、当前处理器模式标志等一些状态位以及一些控制位。
所有的处理器模式都共用一个CPSR
必然会导致冲突,为此,除了User
和Sys
这两个模式以外,其他 7
个模式每个都配备了一个专用的物理状态寄存器,叫做SPSR
(备份程序状态寄存器),当特定的异常中断发生时,SPSR 寄存器用来保存当前程序状态寄存器(CPSR)的值,当异常退出以后可以用SPSR
中保存的值来恢复CPSR
。因为User
和Sys
这两个模式不是异常模式,所以并没有配备SPSR
,因此不能在User
和Sys
模式下访问SPSR
,会导致不可预知的结果。由于SPSR
是CPSR
的备份,因此SPSR
和CPSR
的寄存器结构相同。结构如下图所示:
N(bit31)
:当两个补码表示的有符号整数运算的时候,N=1
表示运算对的结果为负数,N=0
表示结果为正数。Z(bit30)
:Z=1
表示运算结果为零,Z=0
表示运算结果不为零,对于CMP
指令,Z=1
表示进行比较的两个数大小相等。C(bit29)
:在加法指令中,当结果产生了进位,则C=1
,表示无符号数运算发生上溢,其它情况下C=0
。在减法指令中,当运算中发生借位,则C=0
,表示无符号数运算发生下溢,其它情况下C=1
。对于包含移位操作的非加减法运算指令,C
中包含最后一次溢出的位的数值,对于其它非加减运算指令,C
位的值通常不受影响。V(bit28)
:对于加减法运算指令,当操作数和运算结果表示为二进制的补码表示的带符号数时,V=1
表示符号位溢出,通常其他位不影响V
位。Q(bit27)
:仅ARM v5TE_J
架构支持,表示饱和状态,Q=1
表示累积饱和,Q=0
表示累积不饱和。IT[1:0](bit26:25)
:和IT[7:2](bit15:bit10)
一起组成IT[7:0]
,作为IF-THEN
指令执行状态。J(bit24)
:仅ARM_v5TE-J
架构支持,J=1
表示处于Jazelle
状态,此位通常和T(bit5)
位一起表示当前所使用的指令集。
J(bit24) | T(bit5) | 指令类型 |
0 | 0 | ARM |
0 | 1 | Thumb |
1 | 1 | ThumbEE |
1 | 0 | Jazelle |
GE[3:0](bit19
:SIMD
指令有效,大于或等于。IT[7:2](bit15)
:参考IT[1:0]
。E(bit9)
:大小端控制位,E=1
表示大端模式,E=0
表示小端模式。A(bit8)
: 禁止异步中断位,A=1
表示禁止异步中断。I(bit7)
:I=1
禁止IRQ
,I=0
使能IRQ
。F(bit6)
:F=1
禁止FIQ
,F=0
使能FIQ
。T(bit5)
: 控制指令执行状态,表明本指令是ARM
指令还是Thumb
指令,通常和J(bit24)
一起使用表明指令类型,参考J(bit24)
位。M[4:0]
处理器模式控制位, 取值与模式对应情况如下:
M[4:0] | 处理器模式 |
10000 | User模式 |
10001 | FIQ模式 |
10010 | IRQ模式 |
10011 | Supervisor(SVC)模式 |
10110 | Monitor(MON)模式 |
10111 | Abort(ABT)模式 |
11010 | Hyp(HYP)模式 |
11011 | Undef(UND)模式 |
11111 | System(SYS)模式 |
四、ARM
异常处理
1. 什么是异常?
处理器在正常执行程序的过程中可能会遇到一些不正常的事件发生,这时处理器就要将当前的程序暂停下来,转而去处理这个异常的事件,当异常事件处理完成之后再返回到被异常打断的点继续执行程序。
2. ARM
异常源
导致异常产生的事件称为异常源。ARM
中的异常源如下:
FIQ | 快速中断请求引脚有效 |
IRQ | 外部中断请求引脚有效 |
Reset | 复位电平有效 |
Software Interrupt | 执行swi指令 |
Data Abort | 数据终止 |
Prefetch Abort | 指令预取终止 |
Undefined Instruction | 遇到不能处理的指令 |
3. ARM
异常模式
在ARM
的基本工作模式中有5
个属于异常模式,即ARM
遇到异常后会切换成对应的异常模式。异常源对应的异常模式如下:
异常源 | FIQ | IRQ | Reset/SWI | Data Abort/Prefetch Abort | Undef Instruction |
异常模式 | FIQ | IRQ | SVC | Abort | Undef |
4. 异常响应
产生异常时,ARM
进入异常模式,开始处理异常处理程序,处理完异常后回到原来的用户处理程序:
ARM
产生异常后的动作(自动完成)- 1.拷贝
CPSR
中的内容到对应异常模式下的SPSR_<mode>
。 - 2.修改
CPSR
的值。
(1) 修改中断禁止位禁止相应的中断。
(2) 修改模式位进入相应的异常模式。
(3) 修改状态位进入ARM
状态。 - 3.保存返回地址到对应异常模式下的
LR_<mode>
。 - 4.设置
PC
为相应的异常向量(异常向量表对应的地址)。
- 1.拷贝
ARM
异常返回的动作(自己编写)- 5.将
SPSR_<mode>
的值复制给CPSR
使处理器恢复之前的状态。 - 6.将
LR_<mode>
的值复制给PC
使程序跳转回被打断的地址继续执行。
- 5.将
【注意】整个过程CPSR
保存的永远是当前程序运行状态,SPSR
只是异常时对原来的CPSR
进行备份。
5. 异常向量表
当发生异常的时候,程序会跳转到异常向量表,异常向量表的本质是内存中的一段代码。异常向量表中为每个异常源分配了四个字节的存储空间,遇到异常后处理器自动将PC
修改为对应的地址,因为异常向量表空间有限,所以一般我们不会再这里写异常处理程序,而是在对应的位置写一条跳转指令使其跳转到指定的异常处理程序的入口。
【注意】ARM
的异常向量表的基地址默认在0x00
地址,但可以通过配置协处理器来修改其地址。
6. 异常优先级
多个异常产生时,同一时刻不能处理好几个异常吧,异常处理的优先级如下:
7. FIQ
和IRQ
一般来说,FIQ
的响应速度比IRQ
快,原因如下:
- (1)
FIQ
在异常向量表位于最末可直接把异常处理写在异常向量表之后,省去跳转步骤; - (2)
FIQ
模式有5
个私有寄存器(R8-R12
) 执行中断处理程序前无需压栈保存寄存器,可直接处理中断; - (3)
FIQ
的优先级高于IRQ
:
两个中断同时发生时先响应FIQ;
FIQ
可以打断RIQ
,但RIQ
不能打断FIQ
。
8. 异常处理实例
这里以IRQ
异常为例,具体分析一下异常的处理过程,具体过程如下图所示: