68040错误的分支

时间:2011-11-14 05:46:09

标签: 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 / 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的值,看它们是否恢复到正确的值,看起来它们不是。但是,我不是百分之百,我没有修改汇编代码。以下是我为保存寄存器而添加的代码;调试变量的类型为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

总之我的问题是,

1)生成的程序集存在问题,因为它不保存FPSR,FPCR和FPIAR寄存器,并且

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

如果我有另一个编译器进行比较,那将会很棒。不幸的是我无法将调试器附加到代码中。我在C / C ++ / C#/ Java / Python / PHP /等方面有丰富的经验,但我远非装配专家。

感谢任何想法!

2 个答案:

答案 0 :(得分:2)

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

回答您的具体问题:

  

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

我会说是,但只有在ISR中有某些内容影响它们。虽然这似乎不太可能(ISR应该是快速的所以我不希望它们与浮点数混淆),谨慎似乎建议例行保存所有只是关闭 - 代码可能更改它的机会。

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

  

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

再次,这取决于。它看起来没问题,但我有点担心使用特定的内存位置,如fpiar_backupdebug26,除非你非常确定ISR本身不容易另一个中断。

如果在ISR处理过程中禁用了中断,那么你可能还可以。

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

如果您将这些debugX位置的值转出,这将有所帮助,这样您就可以看到ISR的进入和退出之间的值有所不同。并确保它们的尺寸合适。并且要小心,你不会在ISR的中间看着它们,它们几乎肯定会有所不同。

答案 1 :(得分:2)

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