arm - Cortex-M4F 惰性 FPU 堆叠

标签 arm cortex-m context-switch fpu

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

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

Figure 11 Context switching

据此,当PendSV运行时FPCAR应该指向任务 A 的堆栈中保留的空间。但在我看来,因为 CONTROL.FPCA任务 C 高,FPCAR进入 PendSV 时将更新为指向任务 C 的堆栈。如果是这样,S0-S15FPSCR将被保存到任务 C 的堆栈而不是任务 A 的堆栈,这当然是不正确的。

我在这里遗漏了什么,还是 appnote 错了?

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

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

最佳答案

这花了一段时间,但最终我找到了如何尽可能有效地做到这一点。

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

我的第一种方法是操纵 FPCAR , LSPACTEXC_RETURN ,以及 UsageFault 挂起的 PendSV。当然,要做到这一点,FPCAR 必不可少。从惰性堆叠的角度来看,操作不算作 FPU 操作。当文档缺乏时,我们只能从 CPU 中破解答案......

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

确实,我遇到了总线故障。好极了!我用一个有效的地址重复了测试:没有错误,工作完美。所以保存很简单。恢复需要挂起的 PendSV 和操作 FPCAR , LSPACTEXC_RETURN在它里面引起 S0-S15用于在异常返回时恢复当前线程。这里的问题是你不能在它的堆栈上保持当前线程的状态,因为它会被弹出。复制效率低下,所以最好的办法是指向 FPCAR到持久的 TCB 状态,而不是保存 CPU 生成的状态。

这变得非常复杂,它需要在 UsageFault 之后执行 PendSV,并且它有很多极端情况和竞争。有更好的方法。

我最终使用的方法完全在 UsageFault 内部运行并绕过硬件堆栈,而不会因此而降低效率。在启用 FPU 并确定需要 FPU 上下文切换后,我:
  • 套装LSPACT归零;
  • 保存/恢复完整 S0-S31向/从 TCB 的状态;
  • 套装LSPACT回到一。

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

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

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

    关于arm - Cortex-M4F 惰性 FPU 堆叠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38614776/

    相关文章:

    android - 哪个 Android 虚拟设备 (AVD) 更快?

    c - 减法中 16 位 int 机器和 32 位 int 机器之间的不同结果

    c - 我如何使用 crt0.o 在我的裸机 C 程序中设置 .bss 和 .data?

    c - 高效切换堆栈

    c++ - ARMC6 忽略预处理器指令

    c - pt_regs 和 user_struct_regs 的区别

    c - 打开/配置/切换 FRDM-KL46Z GPIO 寄存器以点亮外部 LED/电阻

    用于嵌入式系统的 C++ 数据容器

    operating-system - 发生上下文切换时PC和CPU寄存器?

    java - 非同步i++是否重叠?