【问题标题】:68040 Takes Wrong Branch of If Else68040 If Else 的分支错误
【发布时间】:2011-11-14 05:46:09
【问题描述】:

那里有好的 68k 汇编程序员吗?我正在为摩托罗拉 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/elses 选择了错误的分支。 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/等方面有丰富的经验,但我远非汇编专家。

感谢任何想法!

【问题讨论】:

    标签: compiler-construction assembly 68000 isr


    【解决方案1】:

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

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

    void isr(void)
    {
        // variable declarations ...
    
        __asm("    FMOVE %FPIAR,-(%SP)"); 
        __asm("    FMOVE %FPSR,-(%SP)"); 
    
        // some code ...
    
    
        __asm("    FMOVE (%SP)+,%FPSR"); 
        __asm("    FMOVE (%SP)+,%FPIAR");
    }
    

    【讨论】:

    • 没错,如果你写了一个中断服务程序,你确实需要注意自己正确地做。这意味着保存机器状态,包括状态寄存器。通常编译器无法做到这一点——大多数语言缺乏中断所必需的语言结构,但有些语言具有函数属性或扩展。
    • 我很困惑,你可能会因为添加一个 float 或 double 关键字而受到如此微妙的惩罚。我与 Green Hills 代表进行了更多的交谈,我认为他看到了我的观点,他提出了为这个案例添加文档的请求,并在编译器中添加一个标志来自动保存 FP 寄存器。
    【解决方案2】:

    自 68020 时代以来,我还没有进行过 68K 编程,但我会尝试深入了解相关的灰质和/或网络资源 :-)

    回答您的具体问题:

    生成的程序集是否存在不保存 FPSR、FPCR 和 FPIAR 寄存器的问题?

    我会说是的,但前提是 ISR 中存在影响他们的东西。虽然这似乎不太可能(ISR 应该很快,所以我不认为他们会处理浮点数的东西),但谨慎的做法似乎表明例行程序可以立即保存所有内容-代码可能改变它的机会。

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

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

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

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

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

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

    【讨论】:

    • 感谢您的反馈!我并不真正理解使用特定内存位置的担忧。 “我会有点担心使用 fpiar_backup 或 debug26 之类的特定内存位置,除非您非常确定 ISR 本身不会出现另一个中断。”这些变量只写入那个 ISR。我看不出这会产生什么不利影响。我不确定中断优先级,但有可能另一个中断会干扰。
    • @user1045004:我担心的是,如果在 ISR 运行时发生另一个中断,它可能会覆盖这些值。只需要担心 same 代码运行如此,如果另一个中断是 不同 的,那也没关系。
    猜你喜欢
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    • 2021-06-02
    • 2020-03-20
    • 2018-06-17
    • 1970-01-01
    • 2021-05-25
    • 2016-05-27
    相关资源
    最近更新 更多