此文汇总了Cortex-M3&M4
体系架构常用的知识点,大部分来源于网络博客、书籍、ARM官方文档等。
Ⅰ. 指令集
Cortex-M3
和Cortex-M4
都基于ARMv7-M
架构,Cortex-M
处理器使用的指令集名为Thumb
(其中包括16位Thumb
和更新的32位Thumb
指令),Cortex-M3
和Cortex-M4
使用了Thumb-2
技术,它允许16位和32位指令的混合使用。与ARM7TDMI
等经典的ARM处理器不同的地方是,ARM7TDMI
有两种状态32位的ARM
状态和Thumb
状态,ARM
状态可以很高兴能执行所有指令,而Thumb
状态是16位的,可以节省代码codesize
,两者通常一起使用,但是ARM
状态和Thumb
状态需要切换,而且切换需要一定的开销,这样就导致软件的复杂度提升。而Cortex-M3
和Cortex-M4
用的Thumb-2
可以同时兼容16位的指令和32位的指令。Cortex-M3
和Cortex-M4
是没有经典ARM
处理器的ARM
状态的,处理器可以在任何时候处于Thumb
状态,而不需要任何切换的开销。
Ⅱ. 操作模式和状态
一. 操作状态
A. 调试状态
当处理器被暂停后(例如,通过调试器或触发断点后),就会暂停指令的执行,进入调试状态。
B. Thumb
状态
若处理器在执行代码时,就处于Thumb
状态。Cortex-M
系列处理器不支持ARM
指令,所以没有ARM
状态。
二. 操作模式
A. 处理模式(handler mode
)
在执行中断模式(ISR
)时,为处理模式。在处理模式下,处理器总是处于特权访问等级。
B. 线程模式(thread mode
)
在执行普通的应用代码时,为线程模式。线程模式下,处理器可以处于特权访问等级,也可以处于非特权访问等级。实际的访问等级由特殊寄存器CONTROL
控制。从特权访问等级可以随时切换到非特权访问等级,但是从非特权访问等级切换到特权等级必须借助于异常机制才行。
Ⅲ. 寄存器
Cortex-M3
和Cortex-M4
处理器的寄存器组中有16个寄存器,其中有13个为通用寄存器,剩下三个为特殊寄存器。
一. 通用寄存器r0
~ r12
其中r0
到r12
为通用寄存器,r0
~r7
被称为低寄存器,由于指令中可用的空间有限,许多16位指令只能访问低寄存器,r8
~r12
为高寄存器,可用于32位指令和几个16位指令,低寄存器的初始值是未定义的。
二. 栈指针寄存器r13
(sp
)
r13
为sp
栈指针寄存器,物理上存在两个栈指针:MSP
和PSP
。MSP
为主栈指针(main sp
),是默认的栈指针寄存器,在复位后或者处理器处于处理模式时,都是用的MSP
(进入处理模式后会自动切换到MSP
)。PSP
为线程栈指针(thread sp
),只能用于线程模式(但线程模式可以使用PSP
,也可以使用MSP
)。值得注意的是,RTOS
操作系统内核大多使用的是MSP
,而在用户态或者用户任务中使用的是PSP
。但是如果是裸机的话,一般不需要特别区分。
三. 链接寄存器r14
(lr
)
用于函数或者子程序调用时,返回地址的保存。在函数或者子程序结束时,程序控制可以通过将lr
的数值加载程序计数器pc
中返回调用程序处并继续执行。当执行了函数或子程序调用后,lr
的数值会自动更新。若某函数需要调用另外一个函数或子程序,则他需要首先将lr
的数值保存在栈中,否则,当执行了函数调用后,lr
的当前值会丢失。在异常处理期间,lr
也会被自动更新为特殊的EXC_RETURN
(异常返回)数值,之后该数值会在异常结束时触发异常返回。Cortex-M
处理器中返回地址总是偶数,所以lr
的第0位为0,但是有些跳转或者调用操作需要将lr
的第0比特设为1表示Thumb
状态。
四. 程序计数器r15
(pc
)
pc
寄存器是可读可写的,因为Cortex-M3
和Cortex-M4
只有Thumb
状态,用的全部都是Thumb
指令,所以读pc
寄存器的操作是返回当前指令地址加4。这个是因为流水线的设计(取指->译码->执行)每次取值都合译码相差两个指令流水线阶段,加上Thumb
指令都是以16Bit
为单位的,所以会是+4
。写pc
会引起跳转操作。由于指令需要对齐到半字或字地址,pc
的最低位(LSB
)为0,不过在使用一些跳转/读取存储器指令更新pc
时,需要将新pc
值的LSB
置1以表示Thumb
状态,对于某些高级语言(c/c++
)编译器会自动的将跳转目前的LSB
置位。
五. 特殊寄存器
1. 程序状态寄存器xPSR
xPSR
由三个状态寄存器组成:
应用PSR
: APSR
执行PSR
: EPSR
中断PSR
: IPSR
可以通过MRS
和MSR
操作PSR
来统一访问。
APSR
和IPSR
寄存器可以通过 MRS
和MSR
来分别访问。
EPSR
不能通过MSR
和MRS
直接访问。
标志 | 含义 |
---|---|
N | 负标志 |
Z | 零标志 |
C | 进位(或者非借位)标志 |
V | 溢出标志 |
Q | 饱和标志(ARMv6-M中不存在) |
GE[3:0] | 大于或等于标志,对应每个字节通路(只存在于ARMv7E-M,在ARMv6-M或Cortex-M3中不存在) |
ICT / IT | 中断继续指令(ICI)位,IF-THEN 指令状态位用于条件执行(ARMv6-M则不存在) |
T | Thumb状态,总是1,清除此位会引起错误异常 |
Exception Number | 表示处理器正在处理的异常 |
Q
表示包和运算或饱和调整运算过程中产生了饱和,存在于ARMv7-M
,ARMv6-M
不可用。这个位只能通过写APSR
手动清除。一般的运算指令如果溢出会将MSB
丢失,从而导致结果产生严重的畸变。而饱和运算是将结果强制置为最大值或最小值。饱和运算指令的助记符前都带有Q
,如果QADD16
。Cortex-M3
提供了一些饱和调整指令。Cortex-M4
提供了饱和调整指令和一整套饱和运算指令。
Cortex-M4
中,大于等于(GE
)位域在APSR中占四位,在Coret-M3
中不存在,许多SIMD
指令都会更新该标志。多数情况下,每个位表示SIMD
运算的每一个字节或正或溢出。
2. PRIMASK
、FAULTMASK
和BASEPRI
寄存器
这三个寄存器都是用来异常或中断屏蔽,每一个异常和中断的都有一个优先等级,数值越小的优先级越高。这些特殊寄存器可基于优先等级屏蔽异常,只有在特权访问等级才可以对他们进行操作。默认全是0,即都不屏蔽。
寄存器 | 位宽 | 用途 | 操作方法 |
---|---|---|---|
PRIMASK | 1bit | 阻止不可屏蔽中断(NMI)和HardFault异常之外的所有异常和中断,事实是将当前异常优先级提升到0 | MRS 和 MSR、 CPSIE i 和 CPSID i |
FAULTMASK | 1bit | 阻止不可屏蔽中断(NMI)之外的所有异常和中断,事实是将当前异常优先级提升到1 | MRS 和 MSR、 CPSIE f 和 CPSID f |
BASEPRI | 3~8bit | 根据优先级等级屏蔽异常或者中断,为0时不起作用,为非0时,屏蔽具有相同或更低优先级的异常 | MRS 和 MSR |
3. CONTROL
寄存器
CONTROL
寄存器定义了:
1. 栈指针的选择(主栈指针/进程栈指针)。
2. 线程模式的访问级别(特权/非特权)。
3. 对于具有浮点单元的Cortex-M4
处理器,CONTROL
寄存器中有一位表示当前上下文是否使用浮点计算。
CONTROL
寄存器只能在特权访问等级进行修改,而读取操作都可以。通过MRS
和MSR
指令来访问。
位 | 位置 | 功能 |
---|---|---|
nPRIV | 第0位 | 定义线程模式中的特权等级。为0时,线程模式处于特权等级;为1时,线程模式处于非特权等级 |
SPSEL | 第1位 | 定义栈指针的选择。为0时,线程模式使用主栈指针(MSP); 为1时,线程模式使用进程栈指针(PSP)。在处理模式,该位始终为0,对他的操作会被忽略,也就是说在处理模式只能使用MSP。 |
FPCA | 第2位 | 只存在于浮点有浮点单元的Cortex-M4中,异常处理机制使用该位确定异常产生时浮点单元中的寄存器是否需要保存。为1时,当前上下文使用浮点指令,因此需要保存浮点寄存器。FPCA会在执行浮点指令时自动置位。在异常入口处被硬件清除。 |
复位后,CONTROL
寄存器被置位0。意味这默认状态是线程模式具有特权权限,并且使用主栈指针。通过写CONTROL
寄存器,特权线程模式的程序可以切换栈指针的选择或进入非特权访问等级,不过,nPRIV
(CONTROL
的第0位)置位后,运行在线程模式的程序就不能访问CONTROL
寄存器了。运行在非特权等级的程序无法切换回特权访问等级,这样就提供了一个基本的安全模型。若有必要将处理器在线程模式切换回特权访问等级,则需要使用异常机制。在异常处理程序里可以清除nPRIV
位。在返回到线程模式后,处理器就会进入特权访问等级。
nPRIV | SPSEL | 应用场景 |
---|---|---|
0 | 0 | 简单应用,整个应用运行在特权访问等级,主程序和中断处理只会使用一个栈,也就是MSP |
0 | 1 | 具有嵌入式OS的应用,当前执行的任务运行在特权线程模式,当前任务选择使用进程栈指针(PSP),而MSP则应用与OS内核以及异常处理 |
1 | 0 | 具有嵌入式OS的应用,当前执行的任务运行在非特权线程模式,当前任务选择使用进程栈指针(PSP),而MSP则应用与OS内核以及异常处理 |
1 | 1 | 线程模式运行在非特权访问等级,且使用MSP,处理模式中可见,而用户任务则一般无法使用,这是因为在多数嵌入式OS中,应用任务的栈和OS内核以及异常处理使用的栈是相互独立的 |
在修改了CONTROL
寄存器后,从架构来看,应该使用指令同步屏障(ISB
)指令,以确保本次修改对接下来的代码能起到作用。由于Cortex-M3
、Cortex-M4
、Cortex-M0+
、Cortex-M0
以及Cortex-M1
的流水线非常简单,不使用ISB
只能也不会引起什么问题。
六. 浮点寄存器
1. S0
~ S31
和 D0
~ D15
S0
~ S31
都为32位寄存器,而且每个都可以通过浮点指令访问,或者利用符号D0
~ D15
(D
代表双字/双精度)成都访问。例如,S0
和S1
组成D0
,而S3
和S2
则成对组成D1
。尽管Coretx-M4
中的浮点单元不支持双精度浮点运算,在传输双精度数据时仍可以使用浮点指令。
2. 浮点状态和控制寄存器FPSCR
由于下面的几个原因,FPSCR
中包含了多个位域
1. 定义一些浮点运算动作。
2. 提供浮点运算结果的状态信息。
位 | 描述 |
---|---|
N | 负标志 |
Z | 负标志 |
C | 负标志 |
V | 负标志 |
AHP | 交替半精度控制位,0 : IEEE半精度格式(默认);1 : 交替半精度格式 |
DN | 默认NaN(非数值)模式控制位,0 : NaN操作数会变为浮点运算的输出(默认);1 : 任何设计一个或者多个NaN的运算会返回默认的NaN |
FZ | 清零模式控制位,0 : 清零模式禁止(默认);1 : 清零模式使能 |
RMode | 舍入模式控制位,表示的舍入模式基本上适用于所有的浮点指令,00 : 最近舍入(RN)模式(默认);01 : 正无穷舍入(RP)模式;10 : 负无穷舍入(RM)模式;11 : 向零舍入(RZ)模式 |
IDC | 输入非正常积累异常位,在产生浮点异常时为1,写0则会清除该位(结果未在正常数值范围内) |
IXC | 不精确的积累异常位,在产生浮点异常时为1,写0则会清除该位 |
UFC | 下溢累计异常位,在产生浮点异常时为1,写0则会清除该位 |
OFC | 溢出积累异常位,在产生浮点异常时为1,写0则会清除该位 |
DZC | 被零除积累异常位,在产生浮点异常时为1,写0则会清除该位 |
IOC | 非法操作积累异常位,在产生浮点异常时为1,写0则会清除该位 |
3. 经过存储器映射的浮点单元控制寄存器
除了浮点单元寄存器组和FPSCR
,浮点单元还往系统中引入了一些经过存储器映射的寄存器,如果用于使能和禁止浮点单元的协处理器访问控制寄存器CPACR
。浮点单元默认被禁止以降低功耗。在使用任何浮点指令前,都必须通过变成CPACR
来使能浮点单元。
Ⅳ.存储器系统
Coretx-M
处理器可以对32位存储器进行寻址,储存空间能够达到4GB
。存储器空间是统一的,指令和数据共用相同的地址空间。支持多个特性:
1. 多个总线接口,指令和数据可以同时访问(哈弗总线)。
2. 基于AMBA
(高级微控制总线架构)的总线接口设计:用于存储器和系统总线流水线操作的AHB
(AMBA
高性能总线)Lite
协议,以及用于调试部件通信的APB
(高级外设总线)协议。
3.