工具/软件:
我正在处理一个在中断上下文中需要浮点运算的项目、特别是在快速中断请求 (FIQ) 中。 为了确保保持 FPU 寄存器状态、需要在 ISR 开始时保存 FPU 寄存器并在结束时恢复 根据 A/R 芯片的 ARM 架构参考手册第 B4.1.57 节、我需要保存的寄存器为:
- D0-D15
- D16-D31(如果已实现)
- FPSCR
- FPEXC
此保存/恢复逻辑的原始实现按照上面列出的顺序推入寄存器、并以相反的顺序弹出、如下所示:
uint32 fpscr_reg;
uint32 fpexc_reg;
__asm__(" vpush {d0-d15}");
__asm__(" vmrs %0, fpscr" : "=r"(fpscr_reg));
__asm__(" vmrs %0, fpexc" : "=r"(fpexc_reg));
/* code to handle interrupt... */
__asm__(" vmsr fpexc, %0" ::"r"(fpexc_reg));
__asm__(" vmsr fpscr, %0" ::"r"(fpscr_reg));
__asm__(" vpop {d0-d15}");
这似乎效果很好、但最近、当添加一个新功能时、我发现在单行中执行了几次长浮点运算、得到的结果不正确。 当浮点运算被存储在中间变量中的值分解时、这些错误的结果消失了。
经过大量挖掘后、问题似乎是浮点寄存器的存储顺序错误、这会在进入中断上下文之前显示保存的状态。 对于单行中的长计算、计算状态永远不会保存到 RAM 中、而是生活在 FPU 寄存器中。 当中断触发时、寄存器状态变得混乱、进而影响计算结果。
显然、正确的顺序是 首先存储 FPSCR 和 FPEXC、然后存储通用 FP 寄存器。 如下所示:
uint32 fpscr_reg;
uint32 fpexc_reg;
__asm__(" vmrs %0, fpscr" : "=r"(fpscr_reg));
__asm__(" vmrs %0, fpexc" : "=r"(fpexc_reg));
__asm__(" vpush {d0-d15}");
/* code to handle interrupt... */
__asm__(" vpop {d0-d15}");
__asm__(" vmsr fpexc, %0" ::"r"(fpexc_reg));
__asm__(" vmsr fpscr, %0" ::"r"(fpscr_reg));
这似乎解决了我在单行中进行长浮点计算时遇到的问题。 也就是说、似乎没有太多关于保存/恢复这些步骤的信息。 我希望得到一些确认、确认此新订购是正确的、并且我不会遗漏此过程中的任何其他关键步骤或 TMS570 的习语。
谢谢!