Cortex-M0处理器的异常处理模型

kelly的头像
kelly 发布于:周三, 08/10/2016 - 11:15 ,关键词:

本节主要介绍Cortex-M0的异常处理模型。

1、异常的状态

每个异常都处于以下状态之一:

未激活(Inactive)

异常没有被激活也没有被挂起。

挂起(Pending)

异常正等待被处理器服务。

来自外设或软件的中断请求,能让相应中断变为挂起状态。

激活(Active)

异常正在被处理器服务,并且服务尚未结束。

注意:一个异常处理能中断另一个异常处理,在这种情况下,两个异常都处于激活态。

激活且挂起(Active and pending)

异常正在被处理器服务时,又出现了来自同一异常源的异常。

2、异常类型

异常的类型有:

Reset

复位(Reset)由加电或热复位引起,异常模型把复位当作一个特殊形式的异常。当复位信号有效时,无论指令执行到什么位置,处理器都停止当前的指令。复位信号失效之后,从复位异常规定的入口地址处开始执行,按Thread模式工作。

NMI

不可屏蔽中断(NMI)可由外设引起或软件触发,NMI是除Reset之外,最高优先级的异常,NMI被永久允许,拥有固定的优先级-2。

NMI不能被:

• 任何别的异常屏蔽或阻止。

• 除复位之外的任何异常抢占。

HardFault

硬故障(HardFault)是指在正常情况或异常处理时出现错误(error)所引起的一种异常,硬故障有固定的优先级-1,表明硬故障比任何一个可以配置优先级的异常的优先级都高。

SVCall

超级管理员调用(SuperVisorCall,SVC)是一种由SVC指令触发的异常,在操作系统环境下,应用程序能使用SVC指令访问操作系统内核或设备驱动程序。

PendSV

PendSV是一种中断驱动的请求,用于面向系统级服务。在操作系统环境下,当没有别的异常激活时,使用PendSV进行上下文切换。

SysTick

如果处理器实现系统滴答定时器,那么SysTick是由系统滴答定时器计数到0时所产生的一种异常。软件也能产生SysTick异常,在操作系统环境下,处理器能使用这一异常作为系统滴答计时。

中断(IRQ)

中断(IRQ)是由外设或软件请求而产生的异常,所有的中断对指令的执行是异步进行的。在计算机系统中,外设通过中断与处理器通信。

表1、不同类型异常的优先级

a、为简化软件层,CMSIS仅使用IRQ号,因此采用负数作为异常的编号,IPSR返回异常编号,详见第2-7页的中断程序状态寄存器。

b、有关更多的信息,请看中断向量表。

c、如果处理器没有系统滴答定时器,则异常15保留。

d、IRQ中断号是在处理器实现时定义的,范围是1-32。未实现的IRQ异常编号被保留,例如,如果某处理器仅实现一个IRQ,则异常号17及以上的编号均被保留。

e、见下文的中断优先级寄存器。

f、增长步长为4。

对于异步异常,除Reset外,处理器在异常被触发到异常开始被处理的这段时间内,仍能继续执行指令。
特权软件可以禁止表1中所列出的具有可配置优先级的异常。

3、异常处理

处理器使用以下方式处理异常:

ISRs

中断服务子程序(ISRs)处理IRQ中断异常。

Fault handler

故障处理程序(Faulthandler)处理硬故障。

System handlers

系统处理程序(System handlers)处理系统异常:NMI,PendSV,SVCallSysTick和硬故障。

4、异常向量表

异常向量表包含堆栈指针的复位值,以及起始地址。堆栈指针的复位值和起始地址一起被称为异常向量,用于所有异常处理。图2列出了异常向量表中的异常向量的次序。每一个向量的最低位必须为1,表明异常处理是用Thumb代码实现的。

图2向量表

向量表起始地址固定于0x00000000。

5、异常优先级

如上文中的表1所示,所有的异常都有一个优先级。

• 优先级数值越小,优先级越高。

• 除Reset,HardFault和NMI之外,其余所有异常都能配置其优先级。

如果软件没有配置优先级,那么所有可配置优先级的异常的优先级为0。

注意:可配置优先级的数值范围是0-192,步长为64。Reset、HardFault和NMI是具有负数值的固定优先级异常,比其它异常具有更高的优先级。

给IRQ[0]分配一个较大的优先级数值,而给IRQ[1]分配一个较小的优先级数值,就意味着IRQ[1]比IRQ[0]的优先级高,如果IRQ[1]和IRQ[0]都被触发,则IRQ[1]比IRQ[0]先执行。

如果多个挂起的异常具有同等的优先级,那么具有较小异常号的异常优先执行。例如,如果IRQ[0]和IRQ[1]具有相同的优先级,且都挂起,则IRQ[0]比IRQ[1]优先执行。

当处理器在执行一个异常处理时,如果有更高优先级的异常发生,则该异常可以被抢占。如果发生的异常与正在执行的异常具有相同的优先级,则不管其异常号为多少,正在执行的异常都不会被抢占,而新发生的异常的状态变为挂起。

6、异常处理的进入与返回

描述异常处理的一些术语:

抢占(Preemption)

当处理器在执行一个异常处理时,另一个异常处理可以抢占这个正在被执行的异常处理,只要其优先级比正在被处理的异常优先级高。

一个异常处理抢占另一个异常处理,被称为异常嵌套。

返回(Return)

当没有以下情况时,异常处理结束之后就异常返回:

• 没有挂起的异常需要服务。

• 所完成的异常处理不是一个迟到异常。

处理器从堆栈弹出数据,现场恢复到中断发生之前的状态。

尾链(Tail-chaining)

该机制加速了异常服务。当一个异常处理刚好完成时,若此时有一个挂起的异常满足进入执行的条件,则从堆栈弹出数据的操作就跳过,直接转到这个新的异常处理。

迟到(Late-arriving)

该机制加速抢占。当一个异常处理正在保存状态时,如果出现了一个更高优先级的异常,则处理器切换去执行这个更高优先级的异常,为新异常初始化预取向量。迟到异常并不影响向量的保存,因为两个异常需要保存的状态是一致的。在迟到异常返回时,正常的尾链规则依然有效。

异常进入

有一个具有足够高优先级的挂起异常,以及以下条件之一,则可以进入异常:

• 处理器处于Thread模式。

• 新的异常比正在处理的异常具有更高的优先级。这种情况下,新异常抢占正在执行的异常。

当一个异常抢占另一个异常时,将出现异常嵌套。

足够高优先级的含义是,该异常比屏蔽寄存器的任一有限集的优先级都高,见第2-8页的异常屏蔽寄存器。而比有限集的优先级低的异常就挂起,不执行。当处理器处理一个异常时,除非该异常是一个尾链或迟到的异常,处理器把信息压入当前堆栈,这一操作称为入栈,而这个8字的数据结构被称为一个堆栈帧,堆栈帧包含如下的信息:

入栈后,堆栈指针指向帧的最低地址,堆栈帧是双字地址对齐的。

地址,该地址值保存在堆栈帧信息的PC中,因此被中断程序能恢复现场。处理器从向量表中读取异常处理程序的起始地址,当保护现场的入栈操作完成后,处理器开始执行异常处理程序。与此同时,处理器会将一个EXC_RETURN值写到LR寄存器,这能指明与堆栈信息帧相应的堆栈指针,以及进入异常之前处理器所处的操作模式。

如果在进入异常时没有发生更高优先级的异常,则处理器开始执行该异常处理,并自动把该异常的状态由挂起修改为激活。

如果在进入异常时发生了另一个更高优先级的异常,则处理器将执行高优先级的异常处理,先前的异常的挂起状态保持不变,这属于迟到异常的情况。

异常返回

当处理器处于Handler模式,且执行以下之一指令将PC的值置为EXC_RETURN的值,则发生异常返回:

• 执行POP指令,加载PC寄存器。

• 执行BX指令(任何寄存器均可)。

在异常进入时,处理器把EXC_RETURN的值保存到LR寄存器。处理器根据此数值来决定异常处理完成时的动作。EXC_RETURN值的[31:4]位是0xFFFFFFF,当处理器加载的值与之匹配时,处理器将检测到这不是一个正常的分支操作,而是异常结束。因此,处理器将开始异常返回操作。

EXC_RETURN值的[3:0]位指出所需的返回堆栈以及处理器模式,如表2所示。

表2、异常返回行为

围观 673