compiler-construction - 68040 If Else 走错分支

标签 compiler-construction assembly 68000 isr

有没有好的 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/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/等方面有丰富的经验,但我远不是汇编专家。

任何想法表示赞赏!

最佳答案

为了将来引用,问题确实与编译器没有保存浮点状态寄存器的值有关。我联系了 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");
}

关于compiler-construction - 68040 If Else 走错分支,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8117788/

相关文章:

c - gcc:为简单循环生成的奇怪 asm

c - 为什么 gcc 失败并显示 'unrecognized command line option "-L/lusr/opt/mpfr-2.4.2/lib"'?

debugging - 如何在 QEMU 内使用 GDB 对 x86 代码进行源代码级调试?

c - 为摩托罗拉 68K 处理器编写操作系统。我可以效仿吗?我可以试驾操作系统开发吗?

c - avr中的内联汇编

assembly - EMU8086 将 32 位数字除以 16 位数字给出意外的 0 余数

68000 - 是否有任何摩托罗拉 68k 处理器具有性能计数器?

c++ - 链接器如何知道要链接哪些库?

c++ - Code::Blocks 无法识别 std::thread

java - yacc可以用于为Java 1生成三个地址代码吗?