2

Silicon Labs IDE と SDCC コンパイラを使用して、C 言語で組み込みデバイスのファームウェアを作成しています。デバイスのアーキテクチャは 8051 ファミリに基づいています。問題の関数を以下に示します。この関数は、ステッピング モーターを駆動するように MCU のポートを設定するために使用されます。割り込みハンドラによって呼び出されます。大きな switch ステートメントは、ポートを次のモーター ステップの適切な値に設定するだけです。関数の下部では、ホール効果センサーからの入力と、モーターが失速したかどうかを検出するために移動したステップ数を確認します。問題は、何らかの理由で、このように見える 2 番目の 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 の外観から、コンパイラがこの 2 番目の if ステートメントを最適化していないように見えますが、その場合、なぜ IDE で許可されないので、そこにブレークポイントを設定しますか? 多分それはただのIDEです!

4

4 に答える 4

5

これは「末尾呼び出しの最適化」と呼ばれます。

OperateStepper()は、HandleStallEvent()の呼び出し後は何も実行しないため、OperateStepper()に戻る意味はありません。RETに対してRETを実行するだけで、これは命令とスタックスロットの無駄です

詳細については、「ラムダ:究極の...」MITAIラボのメモをお読みください。

呼び出しではなく、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

最後から 3 行目で、おかしなことが起こっていることに気付きました。への関数呼び出しを行っていませんHandleStallEvent。走り幅跳びをしているので、HandleStallEvent戻れないことは明らかです。また、その上の 2 行では、行番号をジャンプ命令に関連付けるアセンブラ シンボルを定義しています。そのため、678 行のシンボルがあります。IDE で 678 行にブレークポイントを設定できない場合は、678 行の 16 進アドレスを取得して、16 進アドレスに設定することができます。別の試みとして、その行の前のようにローカル変数定義を挿入し、int breakhere = 1中断できる指示が得られるかどうかを確認することもできます。

ところで、CPU は 8 ビットの数値で考えていることがわかるので、short の代わりに char を使用できれば、命令を節約できます。節約された時間に価値があるかどうかは、マシンがこのコード内にいる時間の割合によって異なります。

ところで、この子犬からパフォーマンスを絞り出したい場合、私が組み込み作業を行っていたときに依存していたのは、IDE (または Intel "Blue Box" ICE) をランダムに停止させることでした。ここにそれについての何かがあります。

于 2010-04-15T20:20:32.403 に答える
1

最適化をどのように構成できるかは、コンパイラに依存します。SDCCのマニュアルには、セクション 3.28 にリストされている最適化オプションがあります。コマンド ライン オプションまたはプラグマの両方をソース コード レベルで使用できます。最適化をグローバルに無効にして、同じ効果が得られるかどうかを確認してください。通常、最適化を無効にしてデバッガーでコードをステップ実行すると、ブレークポイントを設定できないという問題が解消されます。これが正常に機能する場合は、プラグマを使用して関数レベルで疑わしい最適化を無効にして、どの最適化が問題を引き起こしているかを確認できます。

于 2010-04-15T20:43:40.870 に答える
1

通常、オプティマイザーは #pragma ステートメントで微調整できます。コンパイラの正確な構文はわかりませんが、コンパイラ/IDE に付属のドキュメントで見つけることができるはずです。

このようなもの

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