中断处理程序中的浮点运算(PowerPC、VxWorks)
我还没有找到任何资源可以准确回答我在我正在开发的软件中看到的问题所试图理解的问题,所以我会在这里向天才们请教!
首先,我在 PowerPC 处理器上运行 VxWorks。
在尝试调试一个单独的问题时,我尝试在中断处理例程中抛出一些快速而肮脏的调试代码。它涉及一个双精度浮点运算来存储感兴趣的值(即,自从我看到最后一个中断进入以来已经过去了多长时间),我后来在运行线程的处理程序之外使用了该值。我没有发现这有什么问题(当然,这需要更长的时间,但时间方面我有足够的时间;中断不会来得太快),但是 VxWorks 肯定不喜欢它。当它到达该代码时,它总是崩溃,这是重新启动系统的严重崩溃之一。我花了一些时间才找到问题根源的双精度操作,我意识到这甚至不是双精度“操作”,甚至从中断中调用的例程返回常量双精度也惨败。
在 PowerPC(或一般的其他体系结构)上,在中断处理程序中执行浮点运算以及在中断处理程序调用的函数中返回浮点(或其他类型)值时通常会出现问题吗?我不知道为什么这会导致程序崩溃。
(解决方法是延迟将自上次中断以来的“ticks”转换为自上次中断以来的“time”,直到代码脱离处理程序,因为它似乎可以很好地处理长整数运算。)
I haven't found any resources that exactly answer what I am trying to understand with an issue I saw in a piece of software I am working on, so I'll ask the geniuses here!
For starters, I'm running with VxWorks on a PowerPC processor.
In trying to debug a separate issue, I tried throwing some quick and dirty debug code in an interrupt handling routine. It involved a double precision floating point operation to store a value of interest (namely, how long it had been since I saw the last interrupt come in) which I used later outside the handler in my running thread. I didn't see a problem in this (sure, it takes longer, but time-wise I had pleanty; the interrupts aren't coming in too quickly) however VxWorks sure didn't like it. It consistently crashes the when it reaches that code, one of the bad crashes that reboots the system. It took me a bit to track down the double operation as the source of the issue, and I realized it's not even double "operations", even returning a constant double from a routine called in the interrupt failed miserably.
On PowerPC (or other architectures in general) are there generally issues doing floating point operations in interrupt handlers and returning floating point (or other type) values in functions called by an interrupt handler? I'm at a loss for why this would cause a program to crash.
(The workaround was to delay the conversion of "ticks" since last interrupt to "time" since laster interrupt until the code is out of the handler, since it seems to handle long integer operations just fine.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
在VxWorks中,每个使用浮点的任务都必须在任务创建时指定,以便在上下文切换期间保存FP寄存器,但仅当从使用浮点的任务切换时才保存。这使得非浮点任务具有更快的上下文切换时间。
然而,当中断抢占浮点任务时,很可能出现不保存 FP 寄存器的情况。为此,中断处理程序需要确定哪个任务被抢占以及它是否已被指定为浮点任务;这将使中断延迟更高且可变,这在实时系统中通常是不希望的。
因此,要使其正常工作,任何使用浮点的中断例程都必须显式保存和恢复 FP 寄存器本身。任何使用浮点的任务在任何情况下都必须如此指定,尽管如果您只有一个这样的任务,您也可以逃脱它。
如果浮点任务被抢占,您的中断将修改该任务使用的浮点寄存器值,当 FP 任务恢复时,结果是不确定的,但包括导致浮点异常 - 如果先前非例如,-zero 寄存器变为零,随后用作除法运算的右侧。
然而在我看来,在这种情况下浮点运算可能完全没有必要。您的“解决方法”实际上是传统的、最安全的和最具确定性的方法,并且可能应该被视为对您的设计的修正,而不是解决方法。
In VxWorks, each task that utilises floating point has to be specified as such in the task creation so that the FP registers are saved during context switches, but only when switching from tasks that use floating point. This allows non-floating point tasks to have faster context switch times.
When an interrupt pre-empts a floating point task however, it is most likely the case that FP registers are not saved. To do so, the interrupt handler would need to determine what task was pre-empted and whether it had been specified as a floating point task; this would make the interrupt latency both higher and variable, which is generally undesirable in a real-time system.
So to make it work any interrupt routine using floating point must explicitly save and restore the FP registers itself. Any task that uses floating point must be specified as such in any case, though you can get away with it if you only have one such task.
If a floating-point task is pre-empted, your interrupt will modify floating point register values in use by that task, the result of this when the FP task resumes is non-deterministic but includes causing a floating point exception - if a previously non-zero register for example, becomes zero, and is subsequently used as the right-hand of a division operation.
It seems to me however that in this case the floating point operation is probably entirely unnecessary. Your "workaround" is in fact the conventional, safest and most deterministic method, and should probably be regarded as a correction of your design rather than a workaround.
您的 ISR 是否调用 fppSave()/fppRestore() 函数?
如果没有,则 ISR 会破坏现有任务可能正在使用的 FP 寄存器。
具体来说,FP 寄存器由 PPC 架构上的 C++ 编译器使用(我认为处理 throw/catch)。
Does your ISR call the fppSave()/fppRestore() functions?
If it doesn't, then the ISR is stomping on FP registers that might be in use by existing tasks.
Specifically, FP registers are used by the C++ compiler on the PPC architecture (I think dealing with throw/catch).
在VxWorks中,至少对于PPC架构来说,浮点运算会导致FP Unavailable Exception。这是因为当中断发生时,MSR 中的 FP 位被清除,因为 VxWorks 假定不会有 FP 操作。这加速了 ISR/任务上下文切换,因为 FP 寄存器不必保存/恢复。
话虽这么说,有一段时间我们有一些调试代码,需要在中断上下文中执行 FP 操作。我们将调用特定 ISR 的 VxWorks 代码更改为 1) 设置 MSR[FP],执行 fpsave 调用,调用 ISR,执行 fprestore 调用,然后清除 MSR[FP]。这让我们解决了这个问题。
话虽这么说,我同意这里其他人的观点,即 FP 操作不应在 ISR 环境中使用,因为 ISR 应该很快,而 FP 操作通常不会。
In VxWorks, at least for the PPC architectures, a floating point operation will cause a FP Unavilable Exception. This is because when an interrupt occurs the FP bit in MSR is cleared because VxWorks assumes that there will be no FP operations. This speeds up ISR/Task context switching because the FP registers do not have to saved/restored.
That being said, there was a time when we had some debug code that we needed FP operations in the interrupt context. We changed the VxWorks code that calls the specific ISR to 1) set the MSR[FP], do a fpsave call, call the ISR, do a fprestore call, then clear the MSR[FP]. This got us around the problem.
That being said, I agree with the rest of the folks here that FP operations should not be used in an ISR context because that ISRs should be fast and FP operations at typically not.
我在开发裸机应用程序时使用过 e300 内核,我可以说,当发生中断时,内核会关闭 FPU,您可以通过检查 MSR 的 FP 位来观察。在对浮点寄存器进行任何操作之前,必须通过向 MSR 的 FP 位写入 1 来重新启用 FPU。然后,您可以根据需要在 ISR 中对 FPU 寄存器进行操作。
I have worked with e300 core while developing bare-metal applications and I can say that when an interrupt occurs, core closes the FPU, that you can observe by checking FP bit of MSR. Before doing anything with the floating point registers, you must re-enable FPU by writing 1 to FP bit of MSR. Then you make operations on FPU registers as you want in an ISR.
VxWorks 中的一般假设是浮点寄存器不需要由 ISR 保存和恢复。主要是因为 ISR 通常不会干扰它们。从历史上看,大多数实时任务也不执行 FP,但这显然已经改变了。不明显的是,许多没有显式使用浮点的任务仍然使用浮点寄存器。我相信任何使用 C++ 编写的代码的任务都使用浮点寄存器(至少在某些处理器/编译器上),即使没有明显的浮点操作。这样的任务应该被赋予FP_? (我忘记了确切的拼写)任务属性,导致它们的 FP reg 在上下文切换期间被保存。
The general assumption in VxWorks is that Floating Point registers don't need to be saved and restored by ISRs. Primarily because ISRs usually don't mess with them. Historically, most real-time tasks didn't do FP either, but that's obviously changed. What's not obvious is that many tasks that don't explicitly use floating point nevertheless use the floating point registers. I believe that any task with code written in C++ uses the floating point registers (at least on some processors/compilers), even though no floating point operations are obvious. Such tasks should be given the FP_? (I forget the exact spelling) task attribute, causing their FP regs to be saved during context switches.
我想您会发现这篇文章很有趣。也许您遇到了浮点异常。
我从未使用过 PowerPC,但我很擅长使用 Google :P
I think you will find this article interesting. Maybe you are getting into a floating point exception.
I never used PowerPC, but I'm good with Google :P