本帖最后由 armstrong 于 2014-10-25 10:37 编辑
今天,在安富莱(armfly)的提醒下,了解了一个重要的Cortex-M4知识;也解除了我一直以来:FPU对任务切换造成开销的顾虑!
CM4内核有个叫lazy stacking的特性,目的是减少没必要的浮点寄存器入栈和出栈时间。该特性默认是使能的,所以不需要关注如何开启。
内核进入中断时,如果曾经使用过FPU指令,就会将EXC_RETURN的bit4清零(通过LR访问);否则bit4为1。
如果EXC_RETURN的bit4清零的状态下,内核会自动入栈S0-S15,FPSCR;当然还有另外8个基础寄存器。
所以,我们的任务切换代码仅需要检测LR的bit4,如果该位为零,就入栈剩下的S16-S31即可;如果该位为1,则根本无需保存FPU寄存器,因为该线程未曾使用过FPU。
不过micrium官方移植是没有考虑这点,它只是粗暴的保存和恢复所有FPU寄存器,用起来虽然不会有错误发生,但是没有利用lazy stacking特性,效率很低很低!
这个知识点说出来如此简单!但是如果不知道这个,你会存在很多对FPU的疑虑。
下面这个,才是我们应该特别注意的。
ARM官方的APPNOTE,专门讲解M4F核的FPU Lazy stacking在上下文切换中的应用。
我大致翻译了一下关键说明:
Lazystacking 特性Cortex-M4F新增了一个叫lazystacking的特性。该特性目的是尽量避免中断延迟,它跳过不必要的FPU寄存器组入栈操作来避免中断延迟。以下情况下是不必要保存FPU寄存器组的:
• 中断服务过程中不使用FPU,或者: • 被中断的线程未曾使用过FPU。 如果中断服务过程使用了FPU并且被中断的线程也使用过FPU, 那么当中断服务过程第一次使用FPU时,FPU寄存器组就必须先保存起来。
Lazy stacking特性是可编程配置的。默认该特性已经开启,软件通过FPCCR寄存器来配置lazy stacking特性。 OS开发者需要特别考虑lazy stacking给线程上下文切换带来的影响。
要确保lazy stacking特性开启,就需要将FPCCR的bit[31](称为ASPEN)和bit[30](称为LSPEN) 都设置为1,这是内核的默认配置。你可以将LSPEN 设置为0来关闭lazy stacking特性。
如果线程曾经使用过FPU, CONTROL寄存器的bit[2](称为FPCA)就会自动置为1。当进入中断时,如果lazy stacking特性已开启,内核就会为FPU预留一个堆栈帧,用于保存FPU的S0-S15和FPSCR寄存器。但是这些FPU寄存器并不会立即入栈,FPCCR 寄存器的bit[0] (称为LSPACT)自动置为1来指示这种状态。EXC_RETURN 的Bit[4]也被清0,用于指示内核已经为FPU预留了堆栈空间,尽管实际上FPU寄存器还没入栈。此后中断服务过程中,有以下情况发生: • 如果中断服务过程没有使用FPU,LSPACT就一直保持为1到中断结束。中断返回时,内核就检测到EXC_RETURN的bit[4]为0并且LSPACT为1,这意味着堆栈已经为FPU预留了空间,而实际上FPU寄存器并未入栈。因此中断返回时就无需出栈,只需返还栈空间即可。 • 如果中断服务过程中使用了FPU,内核就会自动把FPU的S0-S15和FPSCR入栈,LSPACT同时清0。 当中断返回时,内核检测到EXC_RETURN[4]为0并且LSPACT也为0,这意味着FPU寄存器已经入栈;于是内核执行出栈操作恢复FPU寄存器。 如果lazy stacking特性是关闭的,那么内核进入中断时立即入栈FPU寄存器, 退出中断时总是执行FPU的出栈操作。这就增加了中断延迟。
依据你的应用需求,你可以根据Table 2的指示来配置lazy stacking特性:
Table 2 FPCCR setupprocedure LSPEN | ASPEN | Scenarios | 0 | 0 | 关闭FPU寄存器自动保存和lazy stacking特性: 1. In applications without an embedded OS or multi-task scheduler, if none of the interrupt or exception handlers use the FPU. 2. In application code where only one exception handler uses the FPU. If multiple interrupt handlers use the FPU, they must not be permitted to be nested. This can be done by setting them to the same priority level. | 0 | 1 | 关闭Lazy stacking特性,但是自动保存FPU寄存器开启。 CONTROL.FPCA is automatically set to 1 when floating-point is used. At the exception entry, the floating-point registers S0-S15, and FPSCR are pushed to the stack if CONTROL. FPCA is 1. | 1 | 1 | Lazy stacking特性开启,自动保存FPU寄存器开启。 CONTROL.FPCA is automatically set to 1 when floating-point is used. If CONTROL.FPCA is 1 at the exception entry, the processor reserves space in the stack frame and sets LSPACT to 1. But the actual stacking does not happen unless the interrupt handler uses the FPU. | 1 | 0 | 无效配置。 |
armfly的ucos-iii移植,RTT的移植,RTX的移植,应该都是将ASPEN置1,LSPEN清0的模式。大家必须注意这点!如果使用内核的默认配置,这些移植是错误的。
因为如果开启了lazy stacking(LSPEN为1),在执行上下文切换时,S0-S15和FPSCR可能还没有真正入栈!即便EXC_RETURN[4]检测为0。 |