assembly 函数的内联版本失败

2w3rbyxf  于 2023-08-06  发布在  其他
关注(0)|答案(1)|浏览(91)

我一直在写代码与SAMV71Q20B上的硬件寄存器接口。所讨论的函数是:

// Reads current MII link busy status
u32  mii_is_busy(void)
{
    return !GMAC->GMAC_NSR.bit.IDLE;
}

Compiled to Assembly
4B03        ldr r3, =0x40050000
6898        ldr r0, [r3, #8]
F3C00080    ubfx r0, r0, #2, #1
F0800001    eor r0, r0, #1
4770        bx lr
BF00        nop
40050000    .word 0x40050000

Inline version 1
4A05        ldr r2, =0x40050000
6891        ldr r1, [r2, #8]
0749        lsls r1, r1, #29
D1FA        bne 0x0042392C

Inline verison 2
4A08        ldr r2, =0x40050000
6890        ldr r0, [r2, #8]
0740        lsls r0, r0, #29
D507        bpl 0x0042399C

字符串
如果我把它改成

// Reads current MII link busy status
u32 __attribute__ ((noinline)) mii_is_busy(void)
{
    return !GMAC->GMAC_NSR.bit.IDLE;
}


那么它工作正常,程序集是一样的,但是没有内联版本
我们注意到这一点是因为该函数曾经是:

// Reads current MII link busy status
u32 mii_is_busy(void)
{
    return !(GMAC->GMAC_NSR.reg & GMAC_NSR_IDLE);
} 

Compiled to Assembly
4B03        ldr r3, =0x40050000
6898        ldr r0, [r3, #8]
F0800004    eor r0, r0, #4
F3C00080    ubfx r0, r0, #2, #1
4770        bx lr
BF00        nop
40050000    .word 0x40050000


不管是什么原因,它没有被内联,而且工作正常
我所说的工作正常是指我们的整个以太网堆栈对ping有响应,但是做这个小的改变会导致以太网不再工作。
我使用的寄存器的定义来自芯片的CMSIS头。下面是相关的片段

/* -------- GMAC_NSR : (GMAC Offset: 0x08) (R/ 32) Network Status Register -------- */
#if !(defined(__ASSEMBLER__) || defined(__IAR_SYSTEMS_ASM__))
#if COMPONENT_TYPEDEF_STYLE == 'N'
typedef union { 
  struct {
    uint32_t :1;                        /**< bit:      0  Reserved */
    uint32_t MDIO:1;                    /**< bit:      1  MDIO Input Status                        */
    uint32_t IDLE:1;                    /**< bit:      2  PHY Management Logic Idle                */
    uint32_t :4;                        /**< bit:   3..6  Reserved */
    uint32_t RXLPIS:1;                  /**< bit:      7  LPI Indication                           */
    uint32_t :24;                       /**< bit:  8..31  Reserved */
  } bit;                                /**< Structure used for bit  access */
  uint32_t reg;                         /**< Type used for register access */
} GMAC_NSR_Type;
#endif
#endif /* !(defined(__ASSEMBLER__) || defined(__IAR_SYSTEMS_ASM__)) */

#define GMAC_NSR_OFFSET                     (0x08)                                        /**<  (GMAC_NSR) Network Status Register  Offset */

#define GMAC_NSR_MDIO_Pos                   1                                              /**< (GMAC_NSR) MDIO Input Status Position */
#define GMAC_NSR_MDIO_Msk                   (_U_(0x1) << GMAC_NSR_MDIO_Pos)                /**< (GMAC_NSR) MDIO Input Status Mask */
#define GMAC_NSR_MDIO                       GMAC_NSR_MDIO_Msk                              /**< \deprecated Old style mask definition for 1 bit bitfield. Use GMAC_NSR_MDIO_Msk instead */
#define GMAC_NSR_IDLE_Pos                   2                                              /**< (GMAC_NSR) PHY Management Logic Idle Position */
#define GMAC_NSR_IDLE_Msk                   (_U_(0x1) << GMAC_NSR_IDLE_Pos)                /**< (GMAC_NSR) PHY Management Logic Idle Mask */
#define GMAC_NSR_IDLE                       GMAC_NSR_IDLE_Msk                              /**< \deprecated Old style mask definition for 1 bit bitfield. Use GMAC_NSR_IDLE_Msk instead */
#define GMAC_NSR_RXLPIS_Pos                 7                                              /**< (GMAC_NSR) LPI Indication Position */
#define GMAC_NSR_RXLPIS_Msk                 (_U_(0x1) << GMAC_NSR_RXLPIS_Pos)              /**< (GMAC_NSR) LPI Indication Mask */
#define GMAC_NSR_RXLPIS                     GMAC_NSR_RXLPIS_Msk                            /**< \deprecated Old style mask definition for 1 bit bitfield. Use GMAC_NSR_RXLPIS_Msk instead */
#define GMAC_NSR_MASK                       _U_(0x86)                                      /**< \deprecated (GMAC_NSR) Register MASK  (Use GMAC_NSR_Msk instead)  */
#define GMAC_NSR_Msk                        _U_(0x86)                                      /**< (GMAC_NSR) Register Mask  */


我的问题是,我的编译器检查出来了吗,比如它产生了正确的汇编代码吗?因为如果是这样的话,我假设这一定是硬件中的一些微妙之处导致了这一点。我可以只使用我所介绍的两个工作版本中的一个,但我不喜欢在不理解为什么一个工作而另一个不工作的情况下这样做。

vd8tlhqk

vd8tlhqk1#

我想通了,一点也不像寻求帮助,几分钟后就发现了问题。
我的同事写了这段代码:

// Wait for idle status.
// I saw 213 iterations once.
for (i32 i=0; i<500; i++)
    if (!mii_is_busy())
        return ERR_OK;

return ERR_TIMEOUT;

字符串
因此,内联版本的失败是由于执行时间过快,导致循环耗尽迭代。

相关问题