8

那里有什么好的 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

我查看了 Programmer's Reference Manual 并且找不到任何暗示 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/等方面有丰富的经验,但我远非汇编专家。

任何想法表示赞赏!

4

2 回答 2

3

为了将来参考,这个问题确实与编译器没有保存浮点状态寄存器的值有关。我联系了 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");
}
于 2011-11-15T16:19:14.063 回答
2

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

回答您的具体问题:

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

我会说是的,但前提是 ISR 中有影响他们的东西。虽然这似乎不太可能(ISR 应该很快,所以我不希望它们会处理浮点数的东西),但谨慎的做法似乎表明例程会保存所有内容,只是在代码可能会更改它的情况下。

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

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

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

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

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

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

于 2011-11-14T06:24:26.663 回答