GNURX用のCCRXmachine.hとCCRXmachine.cというソースがe2 studioフォルダにありました(内容は概ね名前から予想される通りのものでした)

こんにちは。NoMaYです。

e2 studio v6.3.0がリリースされていたので、インストールして幾つかプロジェクトを作成して、いつものようにe2 studioのインストールフォルダを眺めていたら、CCRXmachine.hとCCRXmachine.cというファイルがあることに気付きました。中を見てみると、概ねファイル名から予想される通りのソースファイルでした。(今までのe2 studioのインストールフォルダを見直してみたところ、以前からあったことが分かりましたが、今まで気付きませんでした。) ただ、一部コメントアウトされているものがあったり、以前に別スレッド『GUNRX用プロジェクトのスマートコンフィグレータのBSPを見ていて気付いた変な移植コード』で話題にしたことと同じ元のコードの意図を理解していない書き換えがあったり、ちょっと惜しいような気もしました。

e2 studioインストールフォルダ\internal\projectgen\rx\Generate\CCRXConversion\inc\CCRXmachine.h



e2 studioインストールフォルダ\internal\projectgen\rx\Generate\CCRXConversion\inc\CCRXmachine.c



Parents
  • こんにちは。NoMaYです。

    GNURX対応のCCRXmachine.cを見ていて、以下のコードの末尾にCC-RXのスタートアップルーチンで見掛けたChange_PSW_PM_to_UserMode()関数の末尾にあるNOP命令が無いことに気付きました。(もっとも、随分以前からCC-RXではビルトイン関数のchg_pmusr()関数が使われるようになっていますので、今はCC-RXでChange_PSW_PM_to_UserMode()関数を見掛けることは余りありませんが。) そのせいで、以下のGNURX対応のCCRXmachine.cのchg_pmusr()関数は誤動作すると思われます。

    CCRXmachine.c

    void chg_pmusr(void)
    {
        __asm("MVFC   PSW,R1" : : :"r1");
        __asm("OR     #00100000h,R1" : : :"r1");
        __asm("PUSH.L R1" : : :"r1");
        __asm("MVFC   PC,R1" : : :"r1");
        __asm("ADD    #10,R1" : : :"r1");
        __asm("PUSH.L R1" : : :"r1");
        __asm("RTE");
    }

    CC-RXのスタートアップルーチンで見掛けたChange_PSW_PM_to_UserMode()関数は以下のコードです。このコードはもともとトリッキーなもので、MVFC PC,R1命令の先頭アドレスに10(0xA)を足したアドレスにRTEして分岐するようになっていますが、その分岐先アドレスは末尾の2つ目のNOP命令の先頭アドレスになります。

    generate\resetprg.c

    #pragma inline_asm Change_PSW_PM_to_UserMode
    static void Change_PSW_PM_to_UserMode(void);

    static void Change_PSW_PM_to_UserMode(void)
    {
        MVFC   PSW,R1
        OR     #00100000h,R1
        PUSH.L R1
        MVFC   PC,R1
        ADD    #10,R1
        PUSH.L R1
        RTE
        NOP
        NOP
    }

    例えば、上のコードをCC-RX V2.03のresetprg.cに組み込んでコンパイルすると以下のようになります。

    generate\resetprg.lst

                                     ;     123 //   _CALL_INIT();                                   // Remove the comment when you use global class object
                                     ;     124
                                     ;     125      set_psw(PSW_init);                              // Set Ubit & Ibit for PSW
    00000031 FD68E0                                 MVTC R14, PSW
                                     ;     126      Change_PSW_PM_to_UserMode();                                    // Remove the comment when you need to change PSW PMbit (SuperVisor->User)
                                                    ._LINE_TOP  inline_asm
    00000034 FD6A01                      MVFC   PSW,R1
    00000037 7731000010                  OR     #00100000h,R1
    0000003C 7EA1                        PUSH.L R1
    0000003E FD6A11                      MVFC   PC,R1    メモ: 0x3E+0xA=0x48
    00000041 62A1                        ADD    #10,R1
    00000043 7EA1                        PUSH.L R1
    00000045 7F95                        RTE
    00000047 03                          NOP
    00000048 03                          NOP
                                                    ._LINE_END  inline_asm
                                     ;     127
                                     ;     128      main();
    00000049 05rrrrrr             A                 BSR _main

    ところが、GNURX対応のCCRXmachine.cのchg_pmusr()関数ではNOP命令がありませんので、GNURXの2018q1でコンパイルしてみると以下のように、分岐先アドレスがchg_pmusr()関数の最後のRTS命令の次のアドレスになってしまいます、、、

    CCRXmachine.lst

     242:../src/CCRXmachine.c **** void chg_pmusr(void)
     243:../src/CCRXmachine.c **** {
     244:../src/CCRXmachine.c ****     __asm("MVFC   PSW,R1" : : :"r1");
     307 00cf FD 6A 01                              MVFC   PSW,R1
     245:../src/CCRXmachine.c ****     __asm("OR     #00100000h,R1" : : :"r1");
     311 00d2 77 31 00 00 10                        OR     #00100000h,R1
     246:../src/CCRXmachine.c ****     __asm("PUSH.L R1" : : :"r1");
     315 00d7 7E A1                                 PUSH.L R1
     247:../src/CCRXmachine.c ****     __asm("MVFC   PC,R1" : : :"r1");
     319 00d9 FD 6A 11                              MVFC   PC,R1    メモ: 0xd9+0xa=0xe3
     248:../src/CCRXmachine.c ****     __asm("ADD    #10,R1" : : :"r1");
     323 00dc 62 A1                                 ADD    #10,R1
     249:../src/CCRXmachine.c ****     __asm("PUSH.L R1" : : :"r1");
     327 00de 7E A1                                 PUSH.L R1
     250:../src/CCRXmachine.c ****     __asm("RTE");
     331 00e0 7F 95                                 RTE
     333 00e2 02                                    rts

     253:../src/CCRXmachine.c **** void set_acc(signed long long data)
     254:../src/CCRXmachine.c **** {
     255:../src/CCRXmachine.c ****  __builtin_rx_mvtachi(data >> 32);
     343 00e3 FD 17 02                              mvtachi r2    メモ: ここはもうchg_pmusr()関数の外部です
     256:../src/CCRXmachine.c ****  __builtin_rx_mvtaclo(data & 0xFFFFFFFF);
     345 00e6 FD 17 11                              mvtaclo r1

    [追記]

    そういえば、以前に別スレッド『RX631のメモリプロテクションユニットの件』で経験しましたが、chg_pmusr()関数(というかChange_PSW_PM_to_UserMode()関数)はIスタックからUスタックへの切り替えが発生しますので、そもそも、インライン展開されない場合には使用方法が難しい関数でもあります。

    なお、CC-RXの場合ですが、これら2つの関数は実装が微妙に異なり、正直に言うと動作確認はしていないのですが、Change_PSW_PM_to_UserMode()関数(≒GNURX対応のCCRXmachine.cのchg_pmusr()関数)はユーザモード中に実行すると特権命令例外が発生すると思われるのに対し、もう一方のchg_pmusr()関数はユーザモード中に実行しても特権命令例外が発生しないと思われます。(理由は、chg_pmusr()関数の方はPSWを調べてユーザモード中だったら特権命令であるRTE命令を実行しないようになっていましたので、そのようになると考えています。)

Reply
  • こんにちは。NoMaYです。

    GNURX対応のCCRXmachine.cを見ていて、以下のコードの末尾にCC-RXのスタートアップルーチンで見掛けたChange_PSW_PM_to_UserMode()関数の末尾にあるNOP命令が無いことに気付きました。(もっとも、随分以前からCC-RXではビルトイン関数のchg_pmusr()関数が使われるようになっていますので、今はCC-RXでChange_PSW_PM_to_UserMode()関数を見掛けることは余りありませんが。) そのせいで、以下のGNURX対応のCCRXmachine.cのchg_pmusr()関数は誤動作すると思われます。

    CCRXmachine.c

    void chg_pmusr(void)
    {
        __asm("MVFC   PSW,R1" : : :"r1");
        __asm("OR     #00100000h,R1" : : :"r1");
        __asm("PUSH.L R1" : : :"r1");
        __asm("MVFC   PC,R1" : : :"r1");
        __asm("ADD    #10,R1" : : :"r1");
        __asm("PUSH.L R1" : : :"r1");
        __asm("RTE");
    }

    CC-RXのスタートアップルーチンで見掛けたChange_PSW_PM_to_UserMode()関数は以下のコードです。このコードはもともとトリッキーなもので、MVFC PC,R1命令の先頭アドレスに10(0xA)を足したアドレスにRTEして分岐するようになっていますが、その分岐先アドレスは末尾の2つ目のNOP命令の先頭アドレスになります。

    generate\resetprg.c

    #pragma inline_asm Change_PSW_PM_to_UserMode
    static void Change_PSW_PM_to_UserMode(void);

    static void Change_PSW_PM_to_UserMode(void)
    {
        MVFC   PSW,R1
        OR     #00100000h,R1
        PUSH.L R1
        MVFC   PC,R1
        ADD    #10,R1
        PUSH.L R1
        RTE
        NOP
        NOP
    }

    例えば、上のコードをCC-RX V2.03のresetprg.cに組み込んでコンパイルすると以下のようになります。

    generate\resetprg.lst

                                     ;     123 //   _CALL_INIT();                                   // Remove the comment when you use global class object
                                     ;     124
                                     ;     125      set_psw(PSW_init);                              // Set Ubit & Ibit for PSW
    00000031 FD68E0                                 MVTC R14, PSW
                                     ;     126      Change_PSW_PM_to_UserMode();                                    // Remove the comment when you need to change PSW PMbit (SuperVisor->User)
                                                    ._LINE_TOP  inline_asm
    00000034 FD6A01                      MVFC   PSW,R1
    00000037 7731000010                  OR     #00100000h,R1
    0000003C 7EA1                        PUSH.L R1
    0000003E FD6A11                      MVFC   PC,R1    メモ: 0x3E+0xA=0x48
    00000041 62A1                        ADD    #10,R1
    00000043 7EA1                        PUSH.L R1
    00000045 7F95                        RTE
    00000047 03                          NOP
    00000048 03                          NOP
                                                    ._LINE_END  inline_asm
                                     ;     127
                                     ;     128      main();
    00000049 05rrrrrr             A                 BSR _main

    ところが、GNURX対応のCCRXmachine.cのchg_pmusr()関数ではNOP命令がありませんので、GNURXの2018q1でコンパイルしてみると以下のように、分岐先アドレスがchg_pmusr()関数の最後のRTS命令の次のアドレスになってしまいます、、、

    CCRXmachine.lst

     242:../src/CCRXmachine.c **** void chg_pmusr(void)
     243:../src/CCRXmachine.c **** {
     244:../src/CCRXmachine.c ****     __asm("MVFC   PSW,R1" : : :"r1");
     307 00cf FD 6A 01                              MVFC   PSW,R1
     245:../src/CCRXmachine.c ****     __asm("OR     #00100000h,R1" : : :"r1");
     311 00d2 77 31 00 00 10                        OR     #00100000h,R1
     246:../src/CCRXmachine.c ****     __asm("PUSH.L R1" : : :"r1");
     315 00d7 7E A1                                 PUSH.L R1
     247:../src/CCRXmachine.c ****     __asm("MVFC   PC,R1" : : :"r1");
     319 00d9 FD 6A 11                              MVFC   PC,R1    メモ: 0xd9+0xa=0xe3
     248:../src/CCRXmachine.c ****     __asm("ADD    #10,R1" : : :"r1");
     323 00dc 62 A1                                 ADD    #10,R1
     249:../src/CCRXmachine.c ****     __asm("PUSH.L R1" : : :"r1");
     327 00de 7E A1                                 PUSH.L R1
     250:../src/CCRXmachine.c ****     __asm("RTE");
     331 00e0 7F 95                                 RTE
     333 00e2 02                                    rts

     253:../src/CCRXmachine.c **** void set_acc(signed long long data)
     254:../src/CCRXmachine.c **** {
     255:../src/CCRXmachine.c ****  __builtin_rx_mvtachi(data >> 32);
     343 00e3 FD 17 02                              mvtachi r2    メモ: ここはもうchg_pmusr()関数の外部です
     256:../src/CCRXmachine.c ****  __builtin_rx_mvtaclo(data & 0xFFFFFFFF);
     345 00e6 FD 17 11                              mvtaclo r1

    [追記]

    そういえば、以前に別スレッド『RX631のメモリプロテクションユニットの件』で経験しましたが、chg_pmusr()関数(というかChange_PSW_PM_to_UserMode()関数)はIスタックからUスタックへの切り替えが発生しますので、そもそも、インライン展開されない場合には使用方法が難しい関数でもあります。

    なお、CC-RXの場合ですが、これら2つの関数は実装が微妙に異なり、正直に言うと動作確認はしていないのですが、Change_PSW_PM_to_UserMode()関数(≒GNURX対応のCCRXmachine.cのchg_pmusr()関数)はユーザモード中に実行すると特権命令例外が発生すると思われるのに対し、もう一方のchg_pmusr()関数はユーザモード中に実行しても特権命令例外が発生しないと思われます。(理由は、chg_pmusr()関数の方はPSWを調べてユーザモード中だったら特権命令であるRTE命令を実行しないようになっていましたので、そのようになると考えています。)

Children
No Data