2

我正在使用 Silicon Labs IDE 和 SDCC 编译器用 C 语言为嵌入式设备编写固件。器件架构基于 8051 系列。有问题的函数如下所示。该功能用于设置我的 MCU 上的端口以驱动步进电机。它被中断处理程序调用。大开关语句只是将端口设置为下一个电机步进的正确值。该功能的底部查看来自霍尔效应传感器的输入和移动的步数,以检测电机是否已停止。问题是,由于某种原因,看起来像这样的第二个 IF 语句if (StallDetector > (GapSize + 20)) { HandleStallEvent(); }似乎总是被优化出来。如果我尝试在HandleStallEvent()调用 IDE 会给我一条消息,说“与此行号没有地址相关性”。我不太擅长阅读汇编来了解它在做什么,但我从下面的 asm 输出中粘贴了一个片段。任何帮助将非常感激。

void OperateStepper(void)
{
    //static bit LastHomeMagState = HomeSensor;
    static bit LastPosMagState = PosSensor;
    if(PulseMotor)
    {
        if(MoveDirection == 1) // Go clockwise
        {
            switch(STEPPER_POSITION) 
            {
                case 'A': 
                     STEPPER_POSITION = 'B';
                     P1 = 0xFD;
                     break;
                case 'B':
                     STEPPER_POSITION = 'C';
                     P1 = 0xFF;
                     break;
                case 'C':
                     STEPPER_POSITION = 'D';
                     P1 = 0xFE;
                     break;
                case 'D':
                     STEPPER_POSITION = 'A';
                     P1 = 0xFC;
                     break; 
                default:
                     STEPPER_POSITION = 'A';
                     P1 = 0xFC;
            }   //end switch
        }
        else                // Go CounterClockwise
        {
            switch(STEPPER_POSITION) 
            {
                case 'A': 
                     STEPPER_POSITION = 'D';
                     P1 = 0xFE;
                     break;
                case 'B': 
                     STEPPER_POSITION = 'A';
                     P1 = 0xFC;
                     break;
                case 'C': 
                     STEPPER_POSITION = 'B';
                     P1 = 0xFD;
                     break;
                case 'D': 
                     STEPPER_POSITION = 'C';
                     P1 = 0xFF;
                     break; 
                default: 
                     STEPPER_POSITION = 'A';
                     P1 = 0xFE;
            }   //end switch
        }   //end else

        MotorSteps++;
        StallDetector++;

        if(PosSensor != LastPosMagState)
        {
            StallDetector = 0;

            LastPosMagState = PosSensor;
        }
        else
        {
            if (PosSensor == ON) 
            {
                if (StallDetector > (MagnetSize + 20))
                {
                    HandleStallEvent();
                }
            }
            else if (PosSensor == OFF) 
            {
                if (StallDetector > (GapSize + 20))
                {
                    HandleStallEvent();
                }
            }
        }

    }   //end if PulseMotor
}

...以及此函数底部的 asm 输出...

;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:653: if(PosSensor != LastPosMagState)
    mov c,_P1_4
    jb  _OperateStepper_LastPosMagState_1_1,00158$
    cpl c
00158$:
    jc  00126$
    C$MotionControl.c$655$3$7 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:655: StallDetector = 0;
    clr a
    mov _StallDetector,a
    mov (_StallDetector + 1),a
    C$MotionControl.c$657$3$7 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:657: LastPosMagState = PosSensor;
    mov c,_P1_4
    mov _OperateStepper_LastPosMagState_1_1,c
    ret
00126$:
    C$MotionControl.c$661$2$8 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:661: if (PosSensor == ON) 
    jb  _P1_4,00123$
    C$MotionControl.c$663$4$9 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:663: if (StallDetector > (MagnetSize + 20))
    mov a,_MagnetSize
    mov r2,a
    rlc a
    subb    a,acc
    mov r3,a
    mov a,#0x14
    add a,r2
    mov r2,a
    clr a
    addc    a,r3
    mov r3,a
    clr c
    mov a,r2
    subb    a,_StallDetector
    mov a,r3
    subb    a,(_StallDetector + 1)
    jnc 00130$
    C$MotionControl.c$665$5$10 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:665: HandleStallEvent();
    ljmp    _HandleStallEvent
00123$:
    C$MotionControl.c$668$2$8 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:668: else if (PosSensor == OFF) 
    jnb _P1_4,00130$
    C$MotionControl.c$670$4$11 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:670: if (StallDetector > (GapSize + 20))
    mov a,#0x14
    add a,_GapSize
    mov r2,a
    clr a
    addc    a,(_GapSize + 1)
    mov r3,a
    clr c
    mov a,r2
    subb    a,_StallDetector
    mov a,r3
    subb    a,(_StallDetector + 1)
    jnc 00130$
    C$MotionControl.c$672$5$12 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:672: HandleStallEvent();
    C$MotionControl.c$678$2$1 ==.
    XG$OperateStepper$0$0 ==.
    ljmp    _HandleStallEvent
00130$:
    ret

在我看来,编译器没有从 asm 的外观优化第二个 if 语句,但如果是这种情况,为什么 IDE 不允许我在此处设置断点?也许这只是一个愚蠢的IDE!

4

4 回答 4

5

它被称为“尾调用优化”。

在调用 HandleStallEvent() 之后,OperateStepper() 不做任何事情,因此返回它没有任何意义。您只是对 RET 执行 RET,这是对指令堆栈槽的浪费。

阅读“Lambda:终极……”麻省理工学院 AI 实验室备忘录了解更多详细信息。

在 HandleStallEvent() 例程而不是调用上设置断点。

于 2010-04-15T21:13:05.510 回答
3

IF 语句没有被优化。这是它的代码。

    C$MotionControl.c$670$4$11 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:670: if (StallDetector > (GapSize + 20))
    mov a,#0x14       ; r2,r3 = 20 + GapSize
    add a,_GapSize    ; (adding a 16-bit number in two 8-bit steps)
    mov r2,a
    clr a
    addc    a,(_GapSize + 1)
    mov r3,a
    clr c
    mov a,r2          ; subtracting in two 8-bit steps
    subb    a,_StallDetector
    mov a,r3
    subb    a,(_StallDetector + 1)
    jnc 00130$        ; jump if carry not set (fall through if carry set)
    C$MotionControl.c$672$5$12 ==.
;   C:\SiLabs\Optec Programs\HSFW_HID_SDCC_2\MotionControl.c:672: HandleStallEvent();
    C$MotionControl.c$678$2$1 ==.
    XG$OperateStepper$0$0 ==.
    ljmp    _HandleStallEvent    ; it knows HandleStallEvent does not return!
00130$:                            ; or rather, it knows this handler cannot return, so there's no need to call.
    ret

我注意到在倒数第三行中,发生了一些有趣的事情。它没有对HandleStallEvent. 它在跳远,所以它显然知道HandleStallEvent不能返回。我还看到,在上面的两行中,它定义了将行号与跳转指令相关联的汇编符号。所以,第 678 行有一个符号。如果 IDE 不允许您在第 678 行设置断点,也许您可​​以获取第 678 行的十六进制地址,并将其设置为十六进制地址。您可能会尝试的另一件事是int breakhere = 1在该行之前插入一个局部变量定义,看看这是否会给您一些可以中断的指令。

顺便说一句,你可以看到 CPU 是按照 8 位数字来思考的,所以如果你可以使用 char 而不是 short,它将节省指令。节省的时间是否值得取决于机器在此代码中的时间百分比。

顺便说一句,如果你想从这只小狗身上榨取性能,我在做嵌入式工作时所依赖的是随机停止 IDE(或英特尔“蓝盒”ICE)。这是关于那个的。

于 2010-04-15T20:20:32.403 回答
1

您通常可以使用 #pragma 语句调整优化器。我不知道您的编译器的确切语法,但您应该能够在您的编译器/ide 随附的文档中找到它。

像这样的东西

#pragma optimize( "", off )
//now the function which should not be optimized
#pragma optimize( "", on )
于 2010-04-15T19:55:08.853 回答
1

如何配置优化取决于编译器。SDCC手册的第 3.28 节列出了优化选项。您可以在源代码级别使用命令行选项或编译指示。尝试全局禁用优化,看看是否得到相同的效果。通常在禁用优化的调试器中单步执行代码将消除无法设置断点的问题。如果这工作正常,您可以尝试使用编译指示在函数级别禁用可疑优化,以查看可能导致问题的优化。

于 2010-04-15T20:43:40.870 回答