68040 If else 的分支错误

发布于 2024-12-15 18:31:59 字数 2793 浏览 2 评论 0原文

有没有好的 68k 汇编程序员?我正在为 Motorola 68040 使用商业 Green Hills 编译器,并且我从代码中看到了一些非常奇怪的行为。有时,代码会进行 if/else 比较,并采取错误的分支。例如:

float a = 1, b = 2;

if (a < b)
    do c;
else 
    do d;

代码有时会变成d!?我发现每当发生此错误时,总会有一个特定的 ISR 中断比较。我查看了 ISR 生成的程序集,发现了一些对我来说没有意义的东西。首先,浮点状态寄存器 FPSR、FPCR 和 FPIAR 似乎没有保存在 ISR 中。这可以解释为什么 if/else 采取了错误的分支。 FPSR 寄存器用于确定比较的结果,如果该寄存器在 ISR 中被覆盖,则分支可能会采取错误的路径。以下是编译器生成的入口和出口程序集:

isr_function:
    FSAVE   -(%SP)
    LINK    %A6,#-192
    MOVEM.L %D0/%D1/%D2/%A0/%A1,-(%SP)
    FMOVEM  %FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7,-(%SP)

    ; isr code ...

    FMOVEM  -308(%A6),%FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7
    MOVEM.L -212(%A6),%D0/%D1/%D2/%A0/%A1
    UNLK    %A6
    FRESTORE    (%SP)+
    RTE

我浏览了《程序员参考手册》,但找不到任何表明 FSAVE 或 FMOVEM 保存 FP 状态寄存器的内容。实际上,我看到一条评论表明事实并非如此,“FSAVE 不保存程序员的浮点单元模型寄存器;它只保存机器的用户不可见部分。”因此,我添加了一些自己的程序集,以在 ISR 开始时保存寄存器,并在最后恢复它们,这极大地提高了性能,但我仍然看到一些问题。以下是我所做的补充;备份变量在 C 代码中输入为 unsigned long:

isr_function:
    FSAVE   -(%SP)
    LINK    %A6,#-192
    MOVEM.L %D0/%D1/%D2/%A0/%A1,-(%SP)
    FMOVEM  %FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7,-(%SP)

    FMOVE %FPIAR,fpiar_backup
    FMOVE %FPSR,fpsr_backup
    FMOVE %FPCR,fpcr_backup

    ; isr code ...

    FMOVE fpiar_backup,%FPIAR
    FMOVE fpsr_backup,%FPSR
    FMOVE fpcr_backup,%FPCR

    FMOVEM  -308(%A6),%FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7
    MOVEM.L -212(%A6),%D0/%D1/%D2/%A0/%A1
    UNLK    %A6
    FRESTORE    (%SP)+
    RTE

我很难相信编译器实际上因不保存寄存器而存在错误。于是我开始查看 FPx 和 Dx 的值,看它们是否恢复到了正确的值,看起来并没有。不过,我并不是 100% 认为我的修改不会污染汇编代码。以下是我添加的用于保存寄存器的代码;调试变量的类型为无符号长整型:

isr_function:
    FMOVE   %FP0,debug3
    FMOVE   %FP1,debug5
    FMOVE   %FP2,debug7
    FMOVE   %FP3,debug9
    FMOVE   %FP4,debug11
    FMOVE   %FP5,debug13
    FMOVE   %FP6,debug15
    FMOVE   %FP7,debug17
    FMOVE   %FPCR,debug19
    FMOVE   %FPIAR,debug23
    FMOVE   %FPSR,debug25   

    FSAVE   -(%SP)
    LINK    %A6,#-192
    MOVEM.L %D0/%D1/%D2/%A0/%A1,-(%SP)
    FMOVEM  %FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7,-(%SP)

    ; isr code ...

    FMOVEM  -308(%A6),%FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7
    MOVEM.L -212(%A6),%D0/%D1/%D2/%A0/%A1
    UNLK    %A6

    FMOVE   %FP0,debug4
    FMOVE   %FP1,debug6
    FMOVE   %FP2,debug8
    FMOVE   %FP3,debug10
    FMOVE   %FP4,debug12
    FMOVE   %FP5,debug14
    FMOVE   %FP6,debug16
    FMOVE   %FP7,debug18
    FMOVE   %FPCR,debug20
    FMOVE   %FPIAR,debug24
    FMOVE   %FPSR,debug26

    FRESTORE    (%SP)+
    RTE

简而言之,我的问题是,

1)生成的程序集是否存在问题,因为它不保存 FPSR、FPCR 和 FPIAR 寄存器,以及

2)我是否正确保存了当我进入和退出 ISR 时寄存器?

如果我有另一个编译器可以比较,那就太好了。不幸的是,我无法将调试器附加到代码中。我在 C/C++/C#/Java/Python/PHP/等方面有丰富的经验,但我距离汇编专家还很远。

任何想法表示赞赏!

Any good 68k assembly programmers out there?? I'm using a commercial Green Hills compiler for a Motorola 68040 and I'm seeing some very strange behavior from the code. Sometimes, the code will do an if/else comparison, and take the wrong branch. For example:

float a = 1, b = 2;

if (a < b)
    do c;
else 
    do d;

The code will sometimes to d!? I've found that whenvever this error occurs, there is always one particular ISR that interrupts the comparison. I took a look at the generated assembly for the ISR and saw a few things that don't make sense to me. First it looks like the floating point status registers, FPSR, FPCR, and FPIAR, are not saved in the ISR. This would explain why the if/elses are taking the wrong branch. The FPSR register is used to determine the result of a comparison, and if that register is overwritten in an ISR then the branch may take the wrong path. Following is the entry and exit assembly generated by the compiler:

isr_function:
    FSAVE   -(%SP)
    LINK    %A6,#-192
    MOVEM.L %D0/%D1/%D2/%A0/%A1,-(%SP)
    FMOVEM  %FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7,-(%SP)

    ; isr code ...

    FMOVEM  -308(%A6),%FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7
    MOVEM.L -212(%A6),%D0/%D1/%D2/%A0/%A1
    UNLK    %A6
    FRESTORE    (%SP)+
    RTE

I looked through the Programmer's Reference Manual and I can't find anything that suggests that FSAVE, or FMOVEM, saves the FP status registers. Actually, I saw one comment that suggests that it does not, "The FSAVE does not save the programmerís model registers of the floating-point unit; it saves only the user invisible portion of the machine." So I added some assembly of my own to save away the registers at the start of the ISR, and restore them at the end, and this dramatically improved the performance, but I'm still seeing some problems. Following are the additions I made; the backup variables are typed as unsigned long in the C code:

isr_function:
    FSAVE   -(%SP)
    LINK    %A6,#-192
    MOVEM.L %D0/%D1/%D2/%A0/%A1,-(%SP)
    FMOVEM  %FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7,-(%SP)

    FMOVE %FPIAR,fpiar_backup
    FMOVE %FPSR,fpsr_backup
    FMOVE %FPCR,fpcr_backup

    ; isr code ...

    FMOVE fpiar_backup,%FPIAR
    FMOVE fpsr_backup,%FPSR
    FMOVE fpcr_backup,%FPCR

    FMOVEM  -308(%A6),%FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7
    MOVEM.L -212(%A6),%D0/%D1/%D2/%A0/%A1
    UNLK    %A6
    FRESTORE    (%SP)+
    RTE

I had a hard time believing the compiler actually had a bug by not saving the registers. So I started looking at the values of FPx and Dx to see that they are restored to the proper value, and it looks like they are not. However I'm not 100% that I'm not tainting the assembly code with my modifications. Following is the code I added to save the registers; the debug variables are typed as unsigned longs:

isr_function:
    FMOVE   %FP0,debug3
    FMOVE   %FP1,debug5
    FMOVE   %FP2,debug7
    FMOVE   %FP3,debug9
    FMOVE   %FP4,debug11
    FMOVE   %FP5,debug13
    FMOVE   %FP6,debug15
    FMOVE   %FP7,debug17
    FMOVE   %FPCR,debug19
    FMOVE   %FPIAR,debug23
    FMOVE   %FPSR,debug25   

    FSAVE   -(%SP)
    LINK    %A6,#-192
    MOVEM.L %D0/%D1/%D2/%A0/%A1,-(%SP)
    FMOVEM  %FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7,-(%SP)

    ; isr code ...

    FMOVEM  -308(%A6),%FP0/%FP1/%FP2/%FP3/%FP4/%FP5/%FP6/%FP7
    MOVEM.L -212(%A6),%D0/%D1/%D2/%A0/%A1
    UNLK    %A6

    FMOVE   %FP0,debug4
    FMOVE   %FP1,debug6
    FMOVE   %FP2,debug8
    FMOVE   %FP3,debug10
    FMOVE   %FP4,debug12
    FMOVE   %FP5,debug14
    FMOVE   %FP6,debug16
    FMOVE   %FP7,debug18
    FMOVE   %FPCR,debug20
    FMOVE   %FPIAR,debug24
    FMOVE   %FPSR,debug26

    FRESTORE    (%SP)+
    RTE

In short my questions are,

1) is there a problem with the generated assembly in that it does not save the FPSR, FPCR, and FPIAR registers, and

2) am I properly saving the values of the registers when I enter and exit the ISR?

It would be great if I had another compiler to compare against. Unfortunately I'm unable to attach a debugger to the code. I have plenty of experience in C/C++/C#/Java/Python/PHP/etc., but I am far from an assembly expert.

Any ideas are appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烟凡古楼 2024-12-22 18:31:59

自从 68020 时代以来,我就没有做过 68K 编程,但我会尝试深入研究相关的灰质和/或网络资源:-)

回答您的具体问题:

生成的程序集是否存在问题,因为它没有保存 FPSR、FPCR 和 FPIAR 寄存器?

我会说是的,但前提是 ISR 中有某些东西影响他们。虽然这似乎不太可能(ISR 应该很快,所以我不认为它们会搞乱浮点的东西),但谨慎起见似乎建议例程在关闭时保存所有内容代码可能可能会改变它。

话虽如此,我不确定你是如何编译 ISR 的(甚至不确定它是否是你的代码)。可能需要一个特殊的标志来让编译器生成更多代码来保存其他内容。

当我进入和退出 ISR 时,我是否正确保存了寄存器的值?

同样,这取决于。看起来不错,但我会有点担心使用特定的内存位置,例如 fpiar_backupdebug26,除非您非常确定 ISR其本身不容易受到另一次中断。

如果在 ISR 处理期间禁用中断,那么您可能没问题。

此外,这还取决于 ISR 所服务的内容。文档似乎表明任何处理浮点问题的 ISR 都应该首先执行 fsave。

如果您转储这些 debugX 位置的值将会很有帮助,这样您就可以看到 ISR 的入口和出口之间有哪些值不同。并确保它们的尺寸合适。请注意,不要在 ISR 中间查看它们,因为它们几乎肯定会有所不同。

I haven't done 68K programming since the days of the 68020 but I'll try to reach down into the relevant gray matter and/or web resources :-)

Answering your specific questions:

Is there a problem with the generated assembly in that it does not save the FPSR, FPCR, and FPIAR registers?

I would say yes, but only if there's something in the ISR that affects them. While this seems unlikely (ISRs are supposed to be fast so I wouldn't expect them to be mucking about with floating point stuff), prudence would seem to suggest that a routine save everything just on the off-chance that code may change it.

Having said that, I'm not sure how you're compiling the ISR (or even whether it's your code at all). It may be that a special flag is necessary to get the compiler to generate more code for saving other things.

Am I properly saving the values of the registers when I enter and exit the ISR?

Again, this depends. It looks okay but I'd be a little worried about using specific memory locations like fpiar_backup or debug26 unless you're very sure that the ISR itself isn't prone to another interrupt.

If the interrupts are disabled during ISR processing then you're probably okay.

In addition, it depends on what that ISR is servicing. The docs seem to indicate that any ISRs servicing floating point problems should always do the fsave first.

It would be helpful if you dumped out the values of those debugX locations so you could see what values are different between entry and exit from the ISR. And make sure they're the right size. And be careful that you're not looking at them in the middle of the ISR, where they'll almost certainly be different.

a√萤火虫的光℡ 2024-12-22 18:31:59

为了将来参考,问题确实与编译器没有保存浮点状态寄存器的值有关。我联系了 Green Hills,据他们说这不是一个错误,保存寄存器的值是程序员的责任。这对我来说很奇怪,因为编译器保存了所有其他内部寄存器,包括 FPU 的内部状态,为什么要停止状态寄存器?

简而言之,保存进入 ISR 和离开 ISR 时的 FPSR 和 FPIAR 的值将纠正该问题。以下应该可以解决问题:

void isr(void)
{
    // variable declarations ...

    __asm("    FMOVE %FPIAR,-(%SP)"); 
    __asm("    FMOVE %FPSR,-(%SP)"); 

    // some code ...


    __asm("    FMOVE (%SP)+,%FPSR"); 
    __asm("    FMOVE (%SP)+,%FPIAR");
}

For future reference, the problem was indeed related to the compiler not saving the value of floating point status registers. I contacted Green Hills and according to them this is not a bug, and that saving the value of the registers is the responsibility of the programmer. Which is odd to me, because the compiler saves all of the other internal registers, including the internal state of the FPU, why stop with the status registers??

In short, saving the value of the FPSR and FPIAR coming into, and when leaving the ISR will correct the problem. The following should do the trick:

void isr(void)
{
    // variable declarations ...

    __asm("    FMOVE %FPIAR,-(%SP)"); 
    __asm("    FMOVE %FPSR,-(%SP)"); 

    // some code ...


    __asm("    FMOVE (%SP)+,%FPSR"); 
    __asm("    FMOVE (%SP)+,%FPIAR");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文