中断的具体行为

中断的具体行为


中断/异常的响应序列

当Cortex-M3处理器开始响应一个中断或异常时,会自动执行一系列操作来保存当前的执行状态,并准备执行中断服务例程(ISR)。这个过程可以分为三个主要步骤:入栈、取向量和更新寄存器。

入栈

响应异常的第一个行动是自动保存现场的必要部分。具体来说,Cortex-M3会依次将以下8个寄存器的值压入适当的堆栈中

  • 入栈顺序

    Cortex-M3会依次将以下8个寄存器的值压入适当的堆栈中:

    1. xPSR(程序状态寄存器)
    2. PC(程序计数器)
    3. LR(链接寄存器)
    4. R12(寄存器12)
    5. R3(寄存器3)
    6. R2(寄存器2)
    7. R1(寄存器1)
    8. R0(寄存器0)
    堆栈选择
    • 如果当前代码正在使用PSP(线程堆栈指针),则这些寄存器的值会被压入PSP管理的堆栈中,即使用线程堆栈。
    • 否则,它们会被压入MSP(主堆栈指针)管理的堆栈中,即使用主堆栈。

    一旦进入了服务例程,将一直使用主堆栈(MSP)。

    堆栈变化

    假设入栈开始时,SP的值为N,则在入栈后,堆栈内部的变化如下表所示:

    堆栈地址寄存器被保存的顺序
    N-4xPSR2
    N-8PC1
    N-12LR8
    N-16R127
    N-20R36
    N-24R25
    N-28R14
    N-32R03

    在这里插入图片描述

    内部入栈顺序

    虽然上述表格显示了寄存器被压入堆栈的顺序,但在Cortex-M3的内部,这个顺序实际上是被打乱的。这种打乱顺序的目的是为了更早地启动服务例程指令的预取(需要修改PC),并在早期更新xPSR中的IPSR位段的值。

    为什么选择这些寄存器

    在ARM架构上,有一套C函数调用标准约定(AAPCS),它规定了函数调用时寄存器的使用方式。Cortex-M3的入栈顺序遵循了这一标准,使得中断服务例程(ISR)可以用C语言编写。编译器优先使用被入栈的寄存器来保存中间结果,从而简化了ISR的编写。

    寄存器压栈的顺序

    R0-R3和R12是最后被压入堆栈的。这样做的原因是为了更容易地使用SP基址来索引寻址,以及为了LDM等多重加载指令(LDM必须加载地址连续的一串数据)。参数的传递也是受益者,使得可以通过压入栈的R0-R3方便地取出参数(主要为系统软件所利用,多见于SVC与PendSV中的参数传递)。

取向量

当Cortex-M3处理器正在进行入栈操作时,指令总线(I-Code总线)也在同时执行另一项重要的任务:从向量表中找出正确的异常向量,并在服务程序的入口处预取指令。这种并行处理的能力得益于Cortex-M3的专用总线设计,使得入栈操作和取指操作可以同时进行。

更新寄存器

  • 在入栈和取向量的工作都完成后,执行服务例程之前,还需要更新一系列的寄存器:

    1. SP(堆栈指针)
      • 在入栈操作中,堆栈指针(PSP或MSP)会被更新到新的位置。
      • 在执行服务例程后,将由MSP负责对堆栈的访问。
    2. PSR(程序状态寄存器)
      • IPSR位段(位于PSR的最低部分)会被更新为新响应的异常编号。
    3. PC(程序计数器)
      • 在向量取出完毕后,PC将指向服务例程的入口地址。
    4. LR(链接寄存器)
      • LR的用法将被重新解释,其值被更新成一种特殊的值,称为“EXC_RETURN”。
      • EXC_RETURN的二进制值除了最低4位外全为1,而其最低4位则有另外的含义(后面会详细解释)。
    EXC_RETURN的含义

    EXC_RETURN是一个特殊的值,用于指示异常返回时的行为。其二进制值的最低4位有特定的含义,如下表所示:

    含义
    31:4全为1
    30表示返回后使用MSP,1表示返回后使用PSP
    20表示返回后进入Handler模式,1表示返回后进入线程模式
    1保留位,必须为0
    0保留位,必须为1
    NVIC中的寄存器更新

    在响应异常时,NVIC(嵌套向量中断控制器)中也会更新相关的寄存器:

    • 悬起位清除:新响应异常的悬起位将被清除。
    • 活动位置位:新响应异常的活动位将被置位。

异常返回

当异常服务例程执行完毕后,需要执行一个“异常返回”动作序列,以恢复先前的系统状态,使被中断的程序得以继续执行。在Cortex-M3中,有三种途径可以触发异常返回序列,如表1-2-1所示。无论使用哪一种途径,都需要用到先前存储的LR的值。

表1-2-1 触发中断返回的指令

返回指令工作原理
BX <reg>当LR存储EXC_RETURN时,使用BX LR即可返回
POP {PC}POP {…,PC}在服务例程中,LR的值常常会被压入栈。此时即可使用POP指令把LR存储的EXC_RETURN往PC里弹,从而激起处理器做中断返回
LDRLDM把PC作为目的寄存器,亦可启动中断返回序列

异常返回的处理流程

在启动了中断返回序列后,下述的处理将进行:

  1. 出栈
    • 先前压入栈中的寄存器在这里恢复。
    • 内部的出栈顺序与入栈时的相对应,堆栈指针的值也改回去。
  2. 更新NVIC寄存器
    • 伴随着异常的返回,它的活动位也被硬件清除。
    • 对于外部中断,如果中断输入再次被置为有效,悬起位也将再次置位,新一次的中断响应序列也可随之再次开始。

嵌套中断

在嵌套中断的场景中,CM3内核和NVIC(Nested Vectored Interrupt Controller)提供了强大的支持,使得中断处理变得更加高效和可靠。

优先级管理

CM3内核和NVIC通过优先级机制来管理中断的嵌套。每个中断都有一个优先级,优先级越低,中断的优先级越高。当一个中断正在处理时,所有优先级不高于它的中断都不能抢占它,包括它自己也不能抢占自己。这种机制确保了中断处理的顺序性和可靠性。

自动入栈和出栈

CM3内核提供了自动入栈和出栈的功能,这意味着在中断发生时,处理器会自动保存当前的上下文(包括寄存器状态)到堆栈中,并在中断处理完成后自动恢复这些上下文。这使得中断服务例程(ISR)可以安全地执行,而不用担心寄存器数据被破坏。

主堆栈容量的管理

尽管自动入栈和出栈机制简化了中断处理,但主堆栈容量的管理仍然是一个关键问题。每次中断嵌套都会增加对主堆栈的需求,每嵌套一级至少需要32字节的堆栈空间。如果主堆栈的容量不足,可能会导致堆栈溢出,进而破坏堆栈中的数据,最终导致系统崩溃或功能紊乱。

为了避免这种情况,开发者需要仔细计算主堆栈的最小安全值,确保在任何可能的中断嵌套深度下,主堆栈都不会溢出。

异常重入问题

CM3内核不允许相同的异常重入。每个异常都有自己的优先级,并且在异常处理期间,同级或低优先级的异常会被阻塞。因此,对于同一个异常,只有在上一次实例的服务例程执行完毕后,才能继续响应新的请求。

例如,在SVC(Supervisor Call)服务例程中,不能再次使用SVC指令,否则会导致fault(故障)。这是因为SVC指令本身会触发一个SVC异常,如果在SVC服务例程中再次使用SVC指令,会导致异常重入,从而引发系统故障。

咬尾中断(Tail-Chaining)

CM3内核通过“咬尾中断”机制显著缩短了中断延迟:

  1. 机制原理:当处理器在响应某个异常时,若发生优先级较低的异常,这些异常会被阻塞。在当前异常返回后,CM3不会重复POP和PUSH寄存器,而是继续使用上一个异常已保存的上下文,从而减少不必要的CPU时间浪费。
  2. 效率提升:这种机制使得两个异常之间的“时间沟”变窄,只需一次入栈/出栈操作,提高了中断处理的效率。

示意图解释

  • 图9.2:展示了异常咬尾机制的流程,减少了中断处理的时间开销。
  • 图9.2B:比较了异常咬尾与常规处理的差异,以ARM7TDMI为例,突出了咬尾中断在减少延迟方面的优势。

在这里插入图片描述

晚到(高优先级)异常

CM3内核的另一个中断处理机制是“晚到异常”,强调了优先级的作用:

  1. 机制原理:当CM3正在响应某个低优先级异常的早期阶段(如入栈阶段),若此时收到高优先级异常的请求,CM3会暂停当前低优先级异常的处理,转而处理高优先级异常。这种情况下,低优先级异常的入栈操作实际上是为高优先级异常服务的。
  2. 处理流程
    • 早期检测:如果在低优先级异常#1的入栈阶段检测到高优先级异常#2,则#2将以“晚到异常”的方式处理,即在入栈完成后立即执行ISR #2。
    • 延迟检测:如果#2来得太晚,已经执行了ISR #1的指令,则按普通抢占处理,这会消耗更多处理器时间和额外32字节的堆栈空间。
  3. 咬尾中断:在ISR #2执行完毕后,CM3会以“咬尾中断”方式启动ISR #1的执行,减少中断延迟。

示意图解释

  • 图9.3:展示了晚到异常的处理模式,说明了在不同时间点检测到高优先级异常时的处理方式。

在这里插入图片描述

中断延迟

在设计实时系统时,中断延迟是一个关键参数,定义为从检测到中断请求到执行其服务例程第一条指令之间的时间。CM3内核通过以下机制确保中断延迟的最小化:

  1. 最小中断延迟:在理想情况下(存储器系统快速且总线系统允许入栈与取指同时进行),CM3的中断延迟固定为12个周期。这12个周期内,处理器完成入栈、取向量、更新寄存器及服务例程取指等操作。
  2. 咬尾中断:在处理咬尾中断时,由于省去了堆栈操作,切入新异常服务例程的时间可缩短至6个周期。
  3. 指令处理
    • 除法和双字传送指令:CM3会取消这些指令的执行,待中断返回后重新开始,以确保中断及时响应。
    • 多重数据传送指令(LDM/STM):CM3支持这些指令的中止和继续,通过在xPSR中记录数据传送进度(ICI位),中断返回后可继续执行。
    • IF-THEN指令:与LDM/STM共享xPSR中的位,若在IF-THEN中使用LDM/STM,则不记录LDM/STM的执行进度,但优先响应中断。
  4. 总线接口:若总线接口上有未完成的数据传送(如带缓冲的写操作),处理器需等待其完成,以确保总线fault服务例程的安全抢占。
  5. 多中断请求:多个中断同时请求时,优先级最高的立即响应,其他中断被延迟。中断嵌套时,每个中断会阻塞同级和低优先级的中断。
  6. 中断掩蔽:中断被掩蔽期间也会增加中断延迟。

异常响应期间的Faults

在CM3内核中,异常响应的每个步骤都可能触发faults,包括入栈、出栈和取向量等阶段。以下是各个阶段的fault处理机制:

入栈期间
  1. 总线Fault
    • 触发条件:入栈期间引起总线fault。
    • 处理方式
      • 若总线fault使能且优先级高于当前异常,则立即响应;否则悬起直到当前异常执行完毕。
      • 若总线fault被除能,则上访至硬fault。
    • 指示位:总线fault状态寄存器(BFSR)的STKERR位(位偏移:4)指示入栈错误。
  2. 存储管理Fault
    • 触发条件:入栈期间引起MPU访问违例。
    • 处理方式:立即执行MemFault服务例程,否则无条件上访至硬fault。
    • 指示位:存储管理fault寄存器(MFSR)的MSTKERR位(位偏移:4)指示入栈时访问违例。
  3. 用法Fault:入栈是自动完成的,因此不可能产生用法fault。
出栈期间
  1. 总线Fault
    • 触发条件:出栈期间引起总线fault。
    • 处理方式
      • 若总线fault使能且优先级高于当前异常,则立即响应;否则悬起直到当前异常执行完毕。
      • 若总线fault被除能,则上访至硬fault。
    • 指示位:BFSR的UNSTKERR位(位偏移:3)指示出栈错误。
  2. 存储管理Fault
    • 触发条件:出栈期间引起MPU访问违例。
    • 处理方式:立即执行MemFault服务例程,否则无条件上访至硬fault。
    • 指示位:MFSR的MUNSTKERR位(位偏移:3)指示出栈时访问违例。
取向量期间
  1. 总线Fault
    • 触发条件:取向量期间发生总线fault。
    • 处理方式:直接上访至硬fault。
    • 指示位:硬fault状态寄存器(HFSR)的VECTTBL位(位偏移:1)指示取向量错误。
无效返回时
  1. 用法Fault
    • 触发条件:LR中的EXC_RETURN不是合法值(如企图返回ARM状态)。
    • 处理方式:引起用法fault,若用法fault被除能,则上访至硬fault。
      **:
    • 触发条件:取向量期间发生总线fault。
    • 处理方式:直接上访至硬fault。
    • 指示位:硬fault状态寄存器(HFSR)的VECTTBL位(位偏移:1)指示取向量错误。
无效返回时
  1. 用法Fault
    • 触发条件:LR中的EXC_RETURN不是合法值(如企图返回ARM状态)。
    • 处理方式:引起用法fault,若用法fault被除能,则上访至硬fault。
    • 指示位:用法Fault状态寄存器(UFSR)的INVPC位(位偏移:2)或INVSTATE位(位偏移:1)指示无效返回。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值