• Cortex-M4中的Tail-chaining(末尾连锁)和Late-arriving(迟到异常)


    1.简介

    Tail-chaining和Late-arriving不知道怎么翻译才恰当,查询网上的翻译分别使用Tail-chaining(末尾连锁)和Late-arriving(迟到异常)比较恰当。

    Tail-chaining(末尾连锁)和Late-arriving(迟到异常)在《STM32 Cortex®-M4 MCUs and MPUs programming manual》手册上 2.3.7 Exception entry and return 章节描述的,网上没有翻译成中文的,这个文档的编号是PM0214,在意法半导体官网可以下载到。

    Tail-chaining(末尾连锁)和Late-arriving(迟到异常)在现在普遍使用C语言编程的情况下,平时很少用到,只要大概知道有这么回事就可以了,但是使用汇编语言编程,移植RTOS时必须对这个一清二楚。

    2.原文

    2.3.7 Exception entry and return

    Descriptions of exception handling use the following terms:

    termdescription
    PreemptionWhen the processor is executing an exception handler,
    an exception can preempt the exception handler if its priority is higher than the priority of the exception being handled.
    See Section 2.3.6: Interrupt priority grouping for more information about preemption by an interrupt.
    When one exception preempts another, the exceptions are called nested exceptions.
    See Exception entry on page 42 more information.
    ReturnThis occurs when the exception handler is completed, and:

    There is no pending exception with sufficient priority to be serviced.
    The completed exception handler was not handling a late-arriving exception.

    The processor pops the stack and restores the processor state to the state it had before the interrupt occurred.
    See Exception return on page 44 for more information.
    Tail-chainingThis mechanism speeds up exception servicing. On completion of an exception handler,
    if there is a pending exception that meets the requirements for exception entry,
    the stack pop is skipped and control transfers to the new exception handler.
    Late-arrivingThis mechanism speeds up preemption.
    If a higher priority exception occurs during state saving for a previous exception,
    the processor switches to handle the higher priority exception and initiates the vector fetch for that exception.
    State saving is not affected by late arrival because the state saved is the same for both exceptions.
    Therefore the state saving continues uninterrupted.
    The processor can accept a late arriving exception until the first instruction of the exception handler
    of the original exception enters the execute stage of the processor.
    On return from the exception handler of the late-arriving exception, the normal tail-chaining rules apply.

    Exception entry

    Exception entry occurs when there is a pending exception with sufficient priority and either:

    • The processor is in Thread mode
    • The new exception is of higher priority than the exception being handled, in which case the new exception preempts the original exception.

    When one exception preempts another, the exceptions are nested.

    Sufficient priority means the exception has more priority than any limits set by the mask registers. For more information see Exception mask registers on page 23. An exception with less priority than this is pending but is not handled by the processor.

    When the processor takes an exception, unless the exception is a tail-chained or a late-arriving exception, the processor pushes information onto the current stack. This operation is referred as stacking and the structure of eight data words is referred as stack frame.

    When using floating-point routines, the Cortex-M4 processor automatically stacks the architected floating-point state on exception entry. Figure 12 on page 43 shows the CortexM4 stack frame layout when floating-point state is preserved on the stack as the result of an interrupt or an exception. Where stack space for floating-point state is not allocated, the stack frame is the same as that of Armv7-M implementations without an FPU. Figure 12 on page 43 also shows this stack frame.

    在这里插入图片描述
    Immediately after stacking, the stack pointer indicates the lowest address in the stack frame. The alignment of the stack frame is controlled via the STKALIGN bit of the Configuration Control Register (CCR).

    The stack frame includes the return address. This is the address of the next instruction in the interrupted program. This value is restored to the PC at exception return so that the interrupted program resumes.

    In parallel to the stacking operation, the processor performs a vector fetch that reads the exception handler start address from the vector table. When stacking is complete, the processor starts executing the exception handler. At the same time, the processor writes an EXC_RETURN value to the LR. This indicates which stack pointer corresponds to the stack frame and what operation mode the was processor was in before the entry occurred.

    If no higher priority exception occurs during exception entry, the processor starts executing the exception handler and automatically changes the status of the corresponding pending interrupt to active.

    If another higher priority exception occurs during exception entry, the processor starts executing the exception handler for this exception and does not change the pending status of the earlier exception. This is the late arrival case.

    Exception return

    Exception return occurs when the processor is in Handler mode and executes one of the following instructions to load the EXC_RETURN value into the PC:

    • an LDM or POP instruction that loads the PC
    • an LDR instruction with PC as the destination
    • a BX instruction using any register.

    EXC_RETURN is the value loaded into the LR on exception entry. The exception mechanism relies on this value to detect when the processor has completed an exception handler. The lowest five bits of this value provide information on the return stack and processor mode. Table 18 shows the EXC_RETURN values with a description of the exception return behavior.

    All EXC_RETURN values have bits[31:5] set to one. When this value is loaded into the PC it indicates to the processor that the exception is complete, and the processor initiates the appropriate exception return sequence.

    Table 18. Exception return behavior

    EXC_RETURN[31:0]Description
    0xFFFFFFF1Return to Handler mode, exception return uses non-floating-point state from the MSP and execution uses MSP after return.
    0xFFFFFFF9Return to Thread mode, exception return uses non-floating-point state from MSP and execution uses MSP after return.
    0xFFFFFFFDReturn to Thread mode, exception return uses non-floating-point state from the PSP and execution uses PSP after return.
    0xFFFFFFE1Return to Handler mode, exception return uses floating-point-state from MSP and execution uses MSP after return.
    0xFFFFFFE9Return to Thread mode, exception return uses floating-point state from MSP and execution uses MSP after return.
    0xFFFFFFEDReturn to Thread mode, exception return uses floating-point state from PSP and execution uses PSP after return.

    3.翻译

    2.3.7 异常进入和退出

    使用下面的术语描述异常处理:

    术语描述
    抢占当处理器正在执行一个异常处理,
    优先级高的异常能抢占当前异常
    参考Section 2.3.6: 中断优先级分组 获取更多关于异常强制的信息.
    当一个异常抢占另一个异常,这些异常被称为嵌套异常.
    参考 异常进入 42页 获取更多信息.
    异常返回异常处理程序完成后,同时满足下列条件,异常退出:

    没有挂起的充足优先级异常需要处理.
    完成的异常处理程序不是迟到异常(注释:迟到异常处理结束后会发生末尾连锁).

    处理器出栈操作并恢复到被打断前的状态.
    参考 44页异常返回 获取更多信息.
    末尾连锁这个机制加速异常处理。
    异常处理一旦完成,假如有挂起的异常满足异常进入条件,出栈被跳过,直接进行新的异常处理。
    迟到异常这个机制加速抢占。
    当前异常正在入栈操作过程中,有一个高优先级异常发生,
    处理器切换到高优先级异常处理,发起高优先级异常向量获取。
    迟到异常并不影响入栈,因为两个异常入栈内容相同。
    因此入栈操作继续进行不被打断。
    处理器能接受迟到异常的最晚时机是:低优先级异常处理程序的第一条指令进入执行阶段之前。
    迟到异常处理程序一旦退出,通常的末尾连锁规则被使用。

    异常进入

    异常进入发生在有充足的优先级异常挂起,并满足以下情况:

    • 处理器在普通用户模式(Thread mode)
    • 新的异常优先级高于正在执行的异常,在这种情况下新的异常抢占当前正在执行的异常。

    当一个异常抢占另一个异常,异常被嵌套。

    充足的优先级意味着异常超出任何mask寄存器限制。参考 23页异常mask寄存器获得更多信息。一个比这低的优先级被挂起但不被处理器处理。

    当处理器执行异常时,除了异常是末尾连锁或迟到异常,处理器推送信息到当前栈。这个操作被称为入栈(stacking) ,这些信息被称为栈帧(stack frame).

    当使用浮点例程,处理器在进入异常时自动入栈结构化的浮点状态信息。在43页图 12 显示了具有浮点信息的栈帧布局。没有浮点信息要保存时,浮点状态占据的空间不被预留,就象Armv7-M无FPU实现在43页图 12 也显示了这种栈帧。
    在这里插入图片描述
    入栈后,栈指针指向栈帧的最低地址。配置控制寄存器(CCR)STKALIGN 位控制栈帧对齐。

    栈帧包含返回地址。这个地址是被打断程序的下一条指向指令的地址。异常返回时这个地址被存储到PC寄存器,以便被打断的程序继续执行。

    在入栈操作的同时,处理器预取异常处理向量表中的异常处理地址。当入栈完成后,处理器执行异常处理;同时,处理器把EXC_RETURN写到LR寄存器中。EXC_RETURN表明哪个栈指针指向栈帧和在进入异常之前处理器操作模式。

    假如在异常进入时没有高优先级异常,处理器开始执行异常处理,并且自动改变相应的挂起中断为活动状态(active)。

    假如在异常进入时有高优先级的异常发生,处理器开始执行高优先级异常处理,这种情况被称为迟到异常。

    异常退出

    当处理器在异常处理模式(Handler mode),执行下面的任意一条指令把EXC_RETURN装载到PC寄存器,异常退出发生:

    • LDM 或 POP 指令装载 PC 寄存器
    • LDR 指令把 PC 寄存器作为目标
    • 使用任何寄存器的BX指令

    异常进入时EXC_RETURN 被装载到 LR 寄存器。当处理器完成异常处理后,异常机制检查这个值。EXC_RETURN最低五位提供返回栈(stack)和处理器模式(processor mode)信息。. 表18 显示EXC_RETURN值对应的异常返回后行为。

    EXC_RETURN[31:5]位全部为1。 当EXC_RETURN被装载到PC寄存器,处理器被指示异常处理完成,接下来处理器发起合适的异常返回处理序列(appropriate exception return sequence)。

    表 18. 异常返回后行为

    EXC_RETURN模式栈帧内容
    0xFFFFFFF1MSP
    返回后使用MSP指向的栈
    返回时使用MSP指向的栈帧内容恢复现场
    Handler
    返回到异常处理模式
    无浮点信息
    0xFFFFFFF9MSP
    返回后使用MSP指向的栈
    返回时使用MSP指向的栈帧内容恢复现场
    Thread
    返回到普通用户模式
    无浮点信息
    0xFFFFFFFDPSP
    返回后使用PSP指向的栈
    返回时使用PSP指向的栈帧内容恢复现场
    Thread
    返回到普通用户模式
    无浮点信息
    0xFFFFFFE1MSP
    返回后使用MSP指向的栈
    返回时使用MSP指向的栈帧内容恢复现场
    Handler
    返回到异常处理模式
    有浮点信息
    0xFFFFFFE9MSP
    返回后使用MSP指向的栈
    返回时使用MSP指向的栈帧内容恢复现场
    Thread
    返回到普通用户模式
    有浮点信息
    0xFFFFFFEDPSP
    返回后使用PSP指向的栈
    返回时使用PSP指向的栈帧内容恢复现场
    Thread
    返回到普通用户模式
    有浮点信息

    4.解释说明

    看懂了吗?翻译没有按照原文直译,而是采用了意译。

    4.1.Late-arriving(迟到异常)

    打个比喻比较恰当,Late-arriving(迟到异常),就像房间,

    有一个人A住之前正在打扫房间,正在打扫时,有另一个B也要住,看到A在打扫,B有特权,对A说你打扫好了我住,A打扫好了B就住进来了

    假如A打扫完后,A住进来了,过段时间B才来,B有特权,B看到A在住,感觉房间被A住脏了,B就会重新打扫再住

    Late-arriving(迟到异常)发生,就像A开始打扫房间到住进房间之前这段时间,B来抢房间,省得自己打扫了。

    Late-arriving(迟到异常)机制是为了加速抢占的,低优先级的异常发生后,正在进行入栈等操作时,高优先级的异常发生时不打断低优先级入栈操作,因为低优先级入栈内容和高优先级入栈内容一样,等到执行异常处理时直接执行高优先级的异常处理。

    4.2.Tail-chaining(末尾连锁)

    Tail-chaining(末尾连锁)用来加速异常处理的,打个比较容易理解的例子,就像在户外舞台演出,

    1. 演出之前需要搭建舞台,布置灯光,桌椅等,
    2. 演出中,每个节目都有不同的人登台表演,表演结束退场;
    3. 演出结束后需要拆除舞台,灯光,移走桌椅等。

    Tail-chaining(末尾连锁)和这个场景很像,

    1. 第一个异常入栈保存环境,
    2. 第一个异常处理,处理完后,接下来一下个挂起的异常处理,处理完再换下一个挂起的异常;
    3. 最后一个挂起的异常处理完后,出栈恢复现场。

    Tail-chaining(末尾连锁)处理多个挂起的异常同时存在时,只需要入栈出栈一次就可以了。

    4.3.Cortex-M4异常处理特点

    4.3.1.尽量减少重复工作

    从Late-arriving(迟到异常)和Tail-chaining(末尾连锁)实现来看,主要减少入栈和出栈的重复工作,在计算机里重复是个很不好的事情,一旦发现重复尽量优化掉,这是一个改进的方向。

    4.3.2.自动化

    能不用人力的时候尽量不用人力,寄存器入栈和出栈使用硬件处理了;入栈完全自动化了,同时预取异常处理函数地址;出栈时只需要一条指令把LR(EXC_RETURN)装载到PC寄存器,加快了入栈和出栈的时间,简化了编译器的设计。以前这些都是编译器做的事情,入栈出栈要保存很多寄存器,需要许多指令周期。这也是改进的一个方向。

    4.3.3.软硬件相互结合优化

    Cortex-M4处理器异常处理入栈出栈的寄存器是把以前编译器的操作硬件化,规范化了。

    这样使用硬件处理加速了处理速度,简化了编译器的处理。有时需要考虑软硬件相互结合优化的方向,这是另一个创新方向。

    总之,经过写这个文章发现Cortex-M4和以前的处理器在异常处理上,改进太多太大了,以前入栈和出栈都要一大堆寄存器,一大堆指令;现在几乎全部自动化了,只要在出栈时使用一条指令把LR寄存器装载到PC寄存器就可以了,并且还有抢占时的Late-arriving(迟到异常)和Tail-chaining(末尾连锁)处理,异常响应实时性大大提高。

    5.最后

    什么时候对浮点信息入栈,这和浮点数Lazy Stacking有关,以后有时间,有机会再研究写一篇关于浮点入栈方面的文章。

  • 相关阅读:
    mysql加密存储敏感数据
    C# I/O流: FileStream
    (二)进制、原码、反码、补码、位运算符
    Code Review最佳实践
    C++中的享元模式
    将企业内容管理(ECM)与企业流程集成的 8 个技巧
    Stm32_标准库_11_ADC_光敏&热敏传感器_测数值
    golang 切片结构体多条件排序
    Proxmox VE软件防火墙的配置
    清朝皇帝年表及1840年后清朝历史事件
  • 原文地址:https://blog.csdn.net/fedorayang/article/details/127735128