Arm Cortex-M4F延迟FPU堆叠

Arm Cortex-M4F延迟FPU堆叠,arm,cortex-m,context-switch,fpu,Arm,Cortex M,Context Switch,Fpu,我正在为Cortex M4F编写线程代码。一切正常,我现在正在研究通过延迟堆叠使FPU上下文切换更有效 我读过ARM的书,并实施了基于禁用FPU和处理UsageFault的替代方法,但硬件未正确保存/恢复较低(S0-S15)寄存器。我认为问题在于图11: 根据这一点,当PendSV运行时,FPCAR应该指向任务A堆栈中保留的空间。但在我看来,由于CONTROL.FPCA在任务C中的位置较高,FPCAR将在输入PendSV时更新为指向任务C的堆栈。如果是这样,S0-S15和FPSCR将被保存到任

我正在为Cortex M4F编写线程代码。一切正常,我现在正在研究通过延迟堆叠使FPU上下文切换更有效

我读过ARM的书,并实施了基于禁用FPU和处理UsageFault的替代方法,但硬件未正确保存/恢复较低(
S0-S15
)寄存器。我认为问题在于图11:

根据这一点,当PendSV运行时,FPCAR应该指向任务A堆栈中保留的空间。但在我看来,由于
CONTROL.FPCA
在任务C中的位置较高,
FPCAR
将在输入PendSV时更新为指向任务C的堆栈。如果是这样,
S0-S15
FPSCR
将被保存到任务C的堆栈中,而不是任务A的堆栈中,这当然是不正确的

我是遗漏了什么,还是appnote错了

一方面,我检查了一些开源RTOS。FreeRTO和mbed RTO总是在上下文切换期间堆叠
S16-S31
,导致自动
S0-S15
堆叠,即它们仅利用延迟堆叠来减少中断延迟,但对任务进行完全状态保留(如appnote中概述的第一种方法)。M4F的TNKernel端口使用UsageFault方法,但通过软件完全保存/恢复
S0-S31
,有效绕过
FPCAR
的任何问题(以48个加载/存储(而不是32个)为代价,16个硬件在恢复时被覆盖)。似乎没有人在使用UsageFault方法的同时只保留
S16-S31


(顺便说一句,这篇文章也发布在了,但很多问题似乎都没有得到回答。如果我在那里得到答案,我也会在这里复制)

花了一段时间,但最终我发现了如何尽可能高效地完成这项工作

首先,appnote是错误的。我对
FPCAR
更新方式的初步解释是正确的。请注意,即使禁用FPU,
FPCAR
也会更新。另外,通过测试,我确定
FPCAR
确实总是指向中断的堆栈

我的第一种方法是操纵
FPCAR
LSPACT
EXC_RETURN
,以及UsageFault PendSV。当然,要做到这一点,从延迟堆叠的角度来看,
FPCAR
操作不算作FPU操作是至关重要的。当缺少文档时,我们只能从CPU中破解答案

LDR  R2, =0xE000EF38
LDR  R3, =0xDEADBEEF
STR  R3, [R2]
VSTM R1, {S16-S31}
UDF
FPCAR
位于
0xE000EF38
<代码>VSTM是上下文保存例程的一部分。其思想是,如果
FPCAR
操作是一个FPU操作,延迟堆叠将停止
FPCAR
存储,并将成功,因为
FPCAR
仍然有效。这将在
UDF
上出现故障。否则,
VSTM
上会发生延迟堆叠,导致损坏的
FPCAR
,从而导致总线故障

事实上,我的车出故障了。耶!我用一个有效的地址重复了测试:没有错误,工作完美。因此,储蓄很简单。恢复需要挂起PendSV并在其内部操纵
FPCAR
LSPACT
EXC_RETURN
,以便在异常返回时恢复当前线程的
S0-S15
。这里的问题是,您不能在堆栈上保留当前线程的状态,因为它将被弹出。复制效率很低,因此最好将
FPCAR
指向持久TCB状态,而不是保存CPU生成的状态

这变得相当复杂,它需要在UsageFault之后执行PendSV,并且它有相当多的角球案例和比赛。有更好的办法

我最终使用的方法完全是在UsageFault内部运行,绕过了硬件堆叠,而不会因此而失去效率。启用FPU并确定需要FPU上下文切换后,I:

  • LSPACT
    设置为零
  • 将完整的
    S0-S31
    状态保存/恢复到TCB或从TCB恢复
  • LSPACT
    设置回1
  • 通过这样做,我可以在整个
    S0-S31
    状态下工作,而不会延迟堆叠,因为CPU认为它已经堆叠了上下文,因为
    LSPACT
    为零。这当然取决于UsageFault处理程序在保存/恢复之外不使用FPU操作,也不被使用ISR的FPU抢占,这是非常简单的假设,因为它是手工编码的ASM,并且故障处理程序不能被ISR抢占。我还尝试通过
    ASPEN
    /
    LSPEN
    禁用延迟堆叠,而不是使用
    LSPACT
    ,但它似乎不起作用(它仍然会触发延迟堆叠,通过设置无效的
    FPCAR
    进行验证)

    效率方面,这与硬件堆叠一样高效。如果我想挑剔,它可以节省一个周期,因为我不需要写回递增的指针


    顺便说一句,我包括了第一种方法,尽管我最终没有使用它,因为我认为如果有其他人来寻找它,其中有一些有用的信息。

    来自应用程序说明:“FPCAR寄存器指向当前堆栈中的一部分堆栈空间…”所以它应该指向抢占任务的堆栈。@DKrueger。但该图暗示,当任务C被PendSV抢占时,它仍然指向任务A的框架。这就是为什么我感到困惑,我不知道我是否误解了它,或者appnote中是否有错误。我认为这表明FPU被禁用时FPCAR将不会更新。这就是为什么它继续指向任务A的堆栈,直到任务C在启用FPU的情况下被抢占。保存FPU上下文可以推迟,直到另一个任务实际需要FPU为止。@DKrueger您有一个很好的假设。appnote说FPCAR更新取决于FPCA,没有提到FPU状态(考虑到它也只能为