RXv3コアのレジスタ一括退避機能の使い方(Register Bank Save Function Usage)を調べてみるスレッド

こんにちは。NoMaYです。

RXv3コア搭載の120MH動作のRXマイコンも、RX66T以降、RX671、RX66N、RX660と品種が増えてきましたが、RXv3コアのセールスポイントの1つであるレジスタ一括退避機能の使い方が今ひとつピンと来ません。そこで、いつものように、ちょっと好奇心からスレッドを立ててみました。(注: RX66Tは、160MHz動作、レジスタ一括退避機能未搭載、です。) いつものように、ぼちぼちと続きます。

ホワイトペーパー
卓越したMCU性能と電力効率を実現するRXv3コア
2019年10月
www.renesas.com/jp/ja/document/whp/introducing-rxv3-core-superior-performance-excellent-power-efficiency#page=6

割り込み応答時間の改善

モータ制御システムなどは、高速な割り込み処理によるリアルタイム性能が必要となってきます。

RXv3コアには、割り込み処理時にレジスタを高速退避/復帰するために、オプション機能として、レジスタ退避バンクと呼ばれる専用メモリを実装しています。図6に示すように、レジスタ退避バンクを使用することで割り込み応答時間を短縮でき、割り込み処理全体の時間を短縮することができます。 割り込み処理ルーチンの中で、SAVE命令を使用すると汎用レジスタとアキュムレータを1クロックで専用メモリに保存できます。RSTR命令は、保存されたレジスタを3~6cycleで復元します。レジスタ退避バンクは専用メモリを複数面持っており、多重割り込みにも対応することが可能です。

図6.割り込み応答時間の改善

レジスタ退避バンクは、割り込みハンドラだけでなく、RTOSコンテキスト切り替えにも使用できます。 RTOSコンテキスト切り替え時間は、レジスタバンク保存機能により最大20%高速化します。


  • こんにちは。NoMaYです。

    ちょっと脱線しますけれども、今回のスレッドで調べ物をしていて、RXマイコンを触り始めて10年目にしてようやく気付いたRXコアのアキュムレータについての驚きの事実がありました。(以前にRL78コアのDTC保留命令というものに気付いた時と同じぐらいの驚きでした。) もっとも、10年目という数字も大雑把ですし、アキュムレータもちゃんと使ったことが無かったですし、ということでもありますけれども。

    (1) メイン処理側でしかアキュムレータを使っていなくても、(適切な割り込み設定をしていないと)割り込み処理の実行後にアキュムレータの値が壊れてしまっていることが有り得る

    (2) 特定の1つのタスクでしかアキュムレータを使っていなくても、(もしも正しいコンテキスト切り替え処理をしていないRTOSカーネルだったら)他のタスクから戻った後にアキュムレータの値が壊れてしまっていることが有り得る

    理由は、以下の画面コピーの説明の通りです。(以下は一例としてRX660のものです。)

    RX660グループ ユーザーズマニュアル ハードウェア編
    R01UH0937JJ0100 Rev.1.00 Pages 2302 2022.03.18
    www.renesas.com/jp/ja/document/mah/rx660-group-users-manual-hardware#page=118


    RXファミリ RXv3命令セットアーキテクチャ ユーザーズマニュアル ソフトウェア編
    R01US0316JJ0100 Rev.1.00 Pages 373 2018.11.20
    www.renesas.com/jp/ja/document/mas/rx-family-rxv3-instruction-set-architecture-users-manual-software-rev100#page=24


    EMUL (普通の算術演算命令)


    EMULU (普通の算術演算命令)


    FMUL (普通の単精度浮動小数点演算命令)


    MUL (普通の算術演算命令)


    RMPA (この積和演算命令はともかくとして)


    [関連リンク]

    RL78コアのDTC保留命令というものについて。

    RL78 FreeRTOS APIを特別なおまじない記述無しで割り込みルーチンから呼び出せるようにしてみた(CC-RL/GNURL78)
    community-ja.renesas.com/cafe_rene/forums-groups/tools/f/forum21/5845/rl78-freertos-api-cc-rl-gnurl78/33975#33975


     

  • こんにちは。NoMaYです。

    またちょっと脱線しますけれども、RL78コアにもレジスタバンクという似た名前のものがあり、それは以下の仕様になっています。ちなみに、RH850コアにはそういうものは無いようです。

    RL78 ファミリ ユーザーズマニュアル ソフトウェア編
    R01US0015JJ0230 Rev.2.30 Pages 245 2022.04.22
    www.renesas.com/jp/ja/document/mah/rl78-family-users-manual-software-rev230





    RH850G3M ユーザーズマニュアル ソフトウェア編
    R01US0123JJ0140 Rev.1.40 Pages 433 2016.12.22
    www.renesas.com/jp/ja/document/mas/rh850g3m-users-manual-software-rev140


    RH850G3MH ユーザーズマニュアル ソフトウェア編
    R01US0143JJ0130 Rev.1.30 Pages 412 2016.12.22
    www.renesas.com/jp/ja/document/man/rh850g3mh-users-manual-software-0


    RH850G3KH ユーザーズマニュアル ソフトウェア編
    R01US0165JJ0120 Rev.1.20 Pages 367 2016.12.22
    www.renesas.com/jp/ja/document/mas/rh850g3kh-users-manual-software



     

  • こんにちは。NoMaYです。

    割り込み関数でレジスタ一括退避機能を使用する場合の各コンパイラの構文は以下の通りです。また、割り込み関数先頭で多重割り込みを許可する場合の構文と、割り込み関数の初めと終わりでアキュムレータの値を退避/復帰させるコードを生成させるコンパイラコマンドラインオプションも書いておきます。

    レジスタ一括退避機能を使用する場合:

    CC-RX : #pragma interrupt <関数名>(bank=バンク番号[,<他の割り込み仕様>])
    ICCRX : #pragma bank=バンク番号
    GNURX : 未サポート

     
    割り込み関数先頭で多重割り込みを許可する場合:

    CC-RX : #pragma interrupt <関数名>(enable[,<他の割り込み仕様>])
    ICCRX : __interrupt __nested void <関数名>(void);
    GNURX : 未サポート

     
    割り込み関数の初めと終わりでアキュムレータの値を退避/復帰させる場合:

    CC-RX : -save_acc (#pragma interruptでも指定可能)
    ICCRX : --save_acc
    GNURX : -msave-acc-in-interrupts

     
    以下、ドキュメントの画面コピーです。

    CC-RX

    途中省略



    ICCRX




    GNURX
    gcc.gnu.org/onlinedocs/gcc/RX-Options.html


    (参) gcc.gnu.org/onlinedocs/gcc/RX-Function-Attributes.html

    (参2) コマンドラインヘルプによるとオンラインドキュメントには未反映のものも残っているようです


     

  • NoMay さんこんにちは。

    色々調査してくれて助かります。

    なるほど、最適化した場合も、危険なコードが出る場合があるようですね。

    ※自分の環境で、ある程度複雑な割り込み関数で、実験してみましたが、それは大丈夫でした。

    自分の最適化は「-O3」です。

    ※デバッグビルド(-O0)は撃沈です・・・

        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
        /*!
            @brief  TPU 制御クラス
            @param[in]  TPU     TPU チャネル・クラス
            @param[in]  TASK    タイマー動作ファンクタ・クラス
            @param[in]  ORDER   ポート・マップ候補型
        */
        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
        template <class TPU, class TASK = utils::null_task, port_map_order::ORDER ORDER = port_map_order::ORDER::FIRST>
        class tpu_io : public tpu_io_base {

            TYPE        type_;
            uint8_t     level_;
            uint8_t     shift_;
            uint32_t    rate_;

            ICU::VECTOR intr_vec_;

            static TASK task_;

    //      static INTERRUPT_FUNC void tpu_task_() noexcept {
            static void tpu_task_() noexcept {
                asm("save #0");
                task_();
                asm("rstr #0");
                asm("rte");
            }

    呼び出し先コード(github にある):

    DSOS_sample/capture.hpp

    アセンブラコード:

    ffc080f0 <__ZN6device6tpu_ioINS_7tpu_x_tILm557328ELNS_10peripheralE27ELNS_5icu_tIvE11VECTOR_SELBE15ELS5_16ELS5_17ELS5_18ELS5_19ELS5_0EEEN4dsos7captureILm16384EE8cap_taskELNS_14port_map_order5ORDERE1EE9tpu_task_Ev>:
    ffc080f0: fd 76 e0 00 save #0
    ffc080f4: fb 5e 2e 90 08 mov.l #0x8902e, r5

    ...

    ffc0814b: fd 76 f0 00 rstr #0
    ffc0814f: 7f 95 rte
    ffc08151: 02 rts

    通常の割り込み関数の場合:

    ffc080f0 <__ZN6device6tpu_ioINS_7tpu_x_tILm557328ELNS_10peripheralE27ELNS_5icu_tIvE11VECTOR_SELBE15ELS5_16ELS5_17ELS5_18ELS5_19ELS5_0EEEN4dsos7captureILm16384EE8cap_taskELNS_14port_map_order5ORDERE1EE9tpu_task_Ev>:
    ffc080f0: 6e ef pushm r14-r15
    ffc080f2: 6e 15 pushm r1-r5
    ffc080f4: fb 5e 2e 90 08 mov.l #0x8902e, r5

    ffc0814b:    6f 15                             popm    r1-r5
    ffc0814d:    6f ef                             popm    r14-r15
    ffc0814f:    7f 95                             rte


    自分はC++17をサポートしていないコンパイラでは自分フレームワークをコンパイル出来ないので、戦力外です。

    C++17 をサポートしているICCRXは選択枠としてはアリですが、コストが見合わないので、結局、GNU-RXがサポートするまで待つしかありません。

    どうしても使いたい場合は、アセンブラソースを sed などで無理やり編集(又は、駄目なコードを吐いたらエラーを出出すなど)するなどの強引な方法も考えられますが・・


    また、GNU-RX(C++) を使う理由として:

    (1) boost が使える

    (2) 最適化が C より深くより高速に動く(経験的な感触)

    (3) 記憶割り当てを使っても、メモリーリークをまずしないように書ける

    (4) より構造的に書けて、些細なミスを防げる

    (5) コードの再利用性

    (6)ヘッダーのみで全て完結するので、ソースをリンクする必要性が無く、管理も簡単

    (7)昔のコードを保守する場合に「楽」だと感じる

    (8)GNU-RXの特性をある程度理解しているので、デバッグがしやすく、対応がしやすい

    利点を上げると沢山ありますが、今更Cでプログラム作る理由が無いので、当面は、GNU-RX一択になるのでしょうね・・・

  • hirakuni45さん、こんにちは。NoMaYです。

    情報どうもありがとうございます。それで、実は、こちら側では、RXスマートコンフィグレータ、というか、FIT/CGの事情になってしまうのですけれども、もろもろのモジュール/コンポーネントにおいて、関数先頭で多重割り込みが許可されるようになっていなくて、ユーザさんが自前で全てコーディングしているような高い割り込み優先度の割り込みの受け付けを、FIT/CGの低い優先度の割り込み処理が邪魔する/遅延させる、ような作りになっていて、ひょっとしたら、100クロックだの1000クロックだの割り込み要求の発生から受け付けまでが遅延するようなこともあるかも知れなくて、そんな構造で、高い割り込み優先度の割り込み関数の先頭処理が、5クロックとか、10クロックとか、20クロックとか、短くなっても価値のあることなのかなぁ、、、という気がしているのです。

    なので、このスレッドの前の方にも書いていますが、小細工を考えないと、、、とか考えていたりするのです。

    hirakuni45さんのように、独自フレームワークで、全ての割り込み処理において処理の早い段階で多重割り込みを許可するように出来る場合には、レジスタ一括退避機能で容易にメリットが出てくる、のですけれども。

    [追記]

    すみません、独り言ですが、ちょっと待ってくださいよ。>> 自分

    GNURXでは、関数先頭で多重割り込みを許可する構文が無いのだから、低い優先度の割り込み処理が、5クロックとか、10クロックとか、20クロックとか、高い優先度の割り込みの受け付けを遅延させることがある筈なのだから、FIT/CGほど酷くは無いけれども、やっぱり、ちょっと、それはもったいないかも、とも思わなくも無いような気もしてきた、かな、、、

  • こんにちは。NoMaYです。

    そういえば、EWRXは、まだ、RX660に対応していませんでしたね。(有償製品版購入ユーザ(保守契約ユーザ?)は、問い合わせすれば、サポートして貰えると思いますけれども。)

    Release notes for the Renesas RX IAR Embedded Workbench product package version 4.20.1
    netstorage.iar.com/SuppDB/Public/UPDINFO/014936/ew/doc/infocenter/ewrx.ENU.html
    RX72NとRX66Nが最後ですね (インストールフォルダを覗くとRX66TはありますがRX671やRX660やRX140が無いですね)

    4.14.1 2020-02-05

    New features

    ・RX72N and RX66N supported
     The RX72N and RX66N groups of microcontrollers are now supported.


    Renesas RX IAR Embedded Workbench製品パッケージバージョン4.20.1のリリースノート
    netstorage.iar.com/SuppDB/Public/UPDINFO/014936/ew/doc/infocenter/ewrx.JPN.html
    同上

    以下、e2 studioの画面コピーです。



    [関連リンク]

    IAR Embedded Workbench for Renesas RX

    製品ページ
    www.iar.com/jp/products/architectures/renesas/iar-embedded-workbench-for-renesas-rx/

    サポートされているデバイス一覧 (こちらにはRX66TもRX671もRX140もありますね(ですがRX660は無いですね))
    www.iar.com/jp/products/architectures/renesas/iar-embedded-workbench-for-renesas-rx/supported-rx-devices/

    無償の評価版
    www.iar.com/jp/products/architectures/renesas/iar-embedded-workbench-for-renesas-rx/#productdownloadpage_3064
     

  • こんにちは。NoMaYです。

    割り込み関数の先頭/末尾でのPUSH/POPが大量になるよう意図的にソースの記述やコンパイルオプションの設定を行い、CC-RXとICCRXとGNURXで生成されたコードを見てみました。e2 studio 2022-07のプロジェクトのファイル一式を以下のzipファイルに固めました。

    issue_RXv3_RegBankSave_20221002.zip

    今回、困惑していることが1つあって、ICCRXで--save_accを指定してもアキュムレータの値を退避/復帰させるコードが生成されませんでした。半日悩んでみましたが、結構深刻なバグ、なのでは?、という考えを解消出来ませんでした。

    以下、生成されたコードの例です。(抜粋です。可能なら割り込み関数先頭で多重割り込み許可にしています。)

    CC-RX : RXv3_RegBankSave_CCRX/HardwareDebug/src/RXv3_RegBankSave_CCRX_ex4.lst

                                            .SECTION    P,CODE
    00000000                         __$i_hdr_4_1:
    00000000 7FA8                           SETPSW I
    00000002 6E4F                           PUSHM R4-R15
    00000004 7EA3                           PUSH.L R3
    00000006 FD1FB3                         MVFACGU #00H, A1, R3
    00000009 7EA2                           PUSH.L R2
    0000000B FD1F82                         MVFACHI #00H, A1, R2
    0000000E 7EA1                           PUSH.L R1
    00000010 FD1F91                         MVFACLO #00H, A1, R1
    00000013 7EA3                           PUSH.L R3
    00000015 FD1F33                         MVFACGU #00H, A0, R3
    00000018 7EA2                           PUSH.L R2
    0000001A FD1F02                         MVFACHI #00H, A0, R2
    0000001D 7EA1                           PUSH.L R1
    0000001F FD1F11                         MVFACLO #00H, A0, R1
    00000022 6E13                           PUSHM R1-R3
    …1行省略…
    0000002A 7100A8                         ADD #0FFFFFFA8H, R0
    …2行省略…
    00000033 6240                           ADD #04H, R0

    …途中省略…

    00000169 710054                         ADD #54H, R0
    0000016C 7EB1                           POP R1
    0000016E 7EB2                           POP R2
    00000170 7EB3                           POP R3
    00000172 FD1711                         MVTACLO R1, A0
    00000175 FD1702                         MVTACHI R2, A0
    00000178 7EB1                           POP R1
    0000017A FD1733                         MVTACGU R3, A0
    0000017D 7EB2                           POP R2
    0000017F 7EB3                           POP R3
    00000181 FD1791                         MVTACLO R1, A1
    00000184 FD1782                         MVTACHI R2, A1
    00000187 FD17B3                         MVTACGU R3, A1
    0000018A 6F1F                           POPM R1-R15
    0000018C 7F95                           RTE

     
    ICCRX : RXv3_RegBankSave_IAR/HardwareDebug/RXv3_RegBankSave_IAR_ex4.lst

       \                                 In section .text, align 8, keep-with-next
       \                     _i_hdr_4_1:
       \   000000 7F A8        SETPSW    I
       \   000002 6E EF        PUSHM     R14-R15
       \   000004 6E 1B        PUSHM     R1-R11
       \   000006 71 00 C8     ADD       #-0x38,SP,SP

    …途中省略…

       \   00011E 71 00 38     ADD       #0x38,SP,SP
       \   000121 6F 1B        POPM      R1-R11
       \   000123 6F EF        POPM      R14-R15
       \   000125 7F 95        RTE

     
    GNURX : RXv3_RegBankSave_GCC/HardwareDebug/RXv3_RegBankSave_GCC_ex4.lst

     136                                    .section    .text.i_hdr_4_1,"ax",@progbits
     138                                _i_hdr_4_1:
     141                                    ; Note: Interrupt Handler
     142 0000 6E 1F                         pushm   r1-r15
     144 0002 FD 1F 11                      mvfaclo #0, A0, r1
     145 0005 FD 1F 02                      mvfachi r2
     146 0008 6E 12                         pushm   r1-r2
     147 000a FD 1F 31                      mvfacgu #0, A0, r1
     148 000d FD 1F 92                      mvfaclo #0, A1, r2
     149 0010 6E 12                         pushm   r1-r2
     150 0012 FD 1F 81                      mvfachi #0, A1, r1
     151 0015 FD 1F B2                      mvfacgu #0, A1, r2
     152 0018 6E 12                         pushm   r1-r2
     153 001a 71 00 C0                      add #-64, r0

    …途中省略…

     452 0165 71 00 40                      add #0x40, r0
     453 0168 6F 12                         popm    r1-r2
     454 016a FD 17 81                      mvtachi r1, A1
     455 016d FD 17 B2                      mvtacgu r2, A1
     456 0170 6F 12                         popm    r1-r2
     457 0172 FD 17 31                      mvtacgu r1, A0
     458 0175 FD 17 92                      mvtaclo r2, A1
     459 0178 6F 12                         popm    r1-r2
     460 017a FD 17 11                      mvtaclo r1
     461 017d FD 17 02                      mvtachi r2
     462 0180 6F 1F                         popm    r1-r15
     465 0182 7F 95                         rte

     

  • こんにちは。NoMaYです。

    割り込み関数でレジスタ一括退避機能を使用してみました。e2 studio 2022-07のプロジェクトのファイル一式を以下のzipファイルに固めました。

    issue_RXv3_RegBankSave_20221003.zip

    ちなみに、レジスタ一括退避先バンク数は、RXv3命令セット上は、最大256バンク持てるようになっていますが、実際の製品では、今のところ、16バンクとなっていますけれども、割り込み優先順位とレジスタ一括退避先バンク番号を常にソースコード上で正しく整合させていれば、16バンクあれば、以下の理由により、全ての割り込みでレジスタ一括退避機能を使用出来るような気がします。

    (1) 割り込み優先順位は16レベルである(ただし最低優先順位にすると割り込み不可となるので実質は15レベルである)
    (2) 多重割り込みを許可しても同一優先順位の割り込みは許可されない(優先順位が高い割り込みのみ許可される)
    (3) レジスタ一括退避先バンク数は16バンクなので割り込み優先順位毎に1つ割り当てることが出来る
    (4) 多重割り込みを許可しても優先順位が高い割り込みのみ許可されるので使用中のバンクを上書きしてしまうことは無い

    以下、生成されたコードの例です。(抜粋です。可能なら割り込み関数先頭で多重割り込み許可にしています。)

    CC-RX : RXv3_RegBankSave_CCRX/HardwareDebug/src/RXv3_RegBankSave_CCRX_ex5.lst

                                            .SECTION    P,CODE
    00000000                         __$i_hdr_5_1:
    00000000 7FA8                           SETPSW I
    00000002 FD76E000                       SAVE #00H
    00000006 7100A8                         ADD #0FFFFFFA8H, R0
    …3行省略…
    00000015 6240                           ADD #04H, R0

    …途中省略…

    0000014E 710054                         ADD #54H, R0
    00000151 FD76F000                       RSTR #00H
    00000155 7F95                           RTE

     
    ICCRX : RXv3_RegBankSave_IAR/HardwareDebug/RXv3_RegBankSave_IAR_ex5.lst

       \                                 In section .text, align 8, keep-with-next
       \                     _i_hdr_5_1:
       \   000000 7F A8        SETPSW    I
       \   000002 FD 76 E0 00  SAVE      #0x0
       \   000006 71 00 C8     ADD       #-0x38,SP,SP

    …途中省略…

       \   00011E 71 00 38     ADD       #0x38,SP,SP
       \   000121 FD 76 F0 00  RSTR      #0x0
       \   000125 7F 95        RTE

     
    GNURX : 未サポート

  • こんにちは。NoMaYです。

    この際ですので、アキュムレータACC0の値が、EMUL、EMULU、FMUL、MULといった命令の実行後に、壊れるのかどうかを実際に見てみました。確かに壊れました。

    以下、CS+の画面コピーです。(以前にe2 studioで困惑する事態があったので、私は今回はCS+です。ひとそれぞれですが。)

    くだんの命令群の実行前


    くだんの命令群の実行後


    試したコード

    #pragma inline_asm code1, code2

    void code1(void)
    {
        MOV.L #12121212H, R6
        MOV.L #34343434H, R7
        MVTACLO R6, A0
        MVTACHI R6, A0
        MVTACGU R6, A0
        MVTACLO R7, A1
        MVTACHI R7, A1
        MVTACGU R7, A1
    }

    void code2(void)
    {
        MOV.L #12121212H, R6
        MOV.L #34343434H, R7
        EMUL R6, R7
        MOV.L #12121212H, R6
        MOV.L #34343434H, R7
        EMULU R6, R7
        MOV.L #0, R6
        MOV.L #0, R7
        FMUL R6, R7
        MOV.L #12121212H, R6
        MOV.L #34343434H, R7
        MUL R6, R7, R8
    }

    int main(void)
    {
        code1();
        __nop();
        code2();
        __nop();
        for(;;);
    }

     

  • こんにちは。NoMaYです。

    FIT/CGの割り込み処理は割り込み関数先頭での多重割り込み許可を設定出来ませんが、そのことが、高い優先度の割り込み処理にて、5クロックとか、10クロックとか、20クロックとか、レジスタ一括退避機能を使用して割り込み応答性を改善したとしても、低い優先度の割り込み処理が実行中かつ多重割り込み不可だった場合には、高い優先度の割り込みが、ひょっとしたら、100クロックとか、1000クロックとか、要求の発生から受け付けまでが遅延するようなこともあるかも知れなくて、そのせいで、数時間はエラー無く動くけれども1日動き続けることは出来ないとか、2,3日は大丈夫だけれども1週間は無理だとか、2,3週間動き続けることも少なく無いけれど1日で止まってしまうこともあるとか、そういう問題に至ってしまう原因の1つになってしまわないかと気掛かりだったりします。

    そこで、FIT/CGの割り込み処理で割り込み関数先頭での多重割り込み許可を設定する手はないかと小細工を考えようとしているのですが、取っ掛かりの候補として以下の2つが思い浮かんでいるところです。


    (1) 以前に、μITRON系RTOSのNORTiで、おまじない処理をFIT/CGの割り込み処理の前に強引に実行させるようにしたやり方の応用

    デメリット:

    ・ FIT/CGの割り込み応答性が数十クロック悪化する (もちろん高い優先度の割り込みの多重割り込みの発生によるものとは別物です)

    メリット:

    ・ 割り込み関数先頭での多重割り込み許可の構文が(今のところ)存在しないGNURXでもそのまま対応可能なはずである
    ・ BSPモジュールのソースに手を入れなくてもよい

    スレッド:

    スマートコンフィグレータの自動生成をカスタマイズしたい
    community-ja.renesas.com/cafe_rene/forums-groups/mcu-mpu/rx/f/forum5/8248/thread/42690#42690

    MISPOさんのNORTiをRX SmartConfiguratorと一緒に使いたい場合の課題と対策を考察してみるスレッド
    community-ja.renesas.com/cafe_rene/forums-groups/tools/f/forum21/8266/mispo-norti-rx-smartconfigurator/42873#42873


    (2) RXスマートコンフィグレータ(というかFIT)のBSPモジュールの3種類コンパイラ対応の為のマクロ定義部に手を入れるやり方

    デメリット:

    ・ 割り込み関数先頭での多重割り込み許可の構文が(今のところ)存在しないGNURXには対応不可能である
    ・ BSPモジュールのソースに手を入れることになる

    メリット:

    ・FIT/CGの割り込み応答性は1クロック遅くなるのみです (もちろん高い優先度の割り込みの多重割り込みの発生によるものは別物です)

    ソース:

    現状のBSPモジュールのV7.20のr_bsp/mcu/all/r_rx_compiler.hから抜粋したままのもの

    #if defined(__CCRX__)

    /* Standard */
    #if BSP_CFG_RTOS_USED == 4    /* Renesas RI600V4 & RI600PX */
    #define R_BSP_PRAGMA_INTERRUPT(function_name, vector)                 extern void function_name(void);

    #define R_BSP_PRAGMA_STATIC_INTERRUPT(function_name, vector)          void function_name(void);

    #define R_BSP_PRAGMA_INTERRUPT_FUNCTION(function_name)                extern void function_name(void);

    #else /* BSP_CFG_RTOS_USED != 4*/
    #define R_BSP_PRAGMA_INTERRUPT(function_name, vector)                 R_BSP_PRAGMA(interrupt function_name(vect=vector))\
                                                                          extern void function_name(void);
    #define R_BSP_PRAGMA_STATIC_INTERRUPT(function_name, vector)          R_BSP_PRAGMA(interrupt function_name(vect=vector))\
                                                                          static void function_name(void);

    #define R_BSP_PRAGMA_INTERRUPT_FUNCTION(function_name)                R_BSP_PRAGMA(interrupt function_name)\
                                                                          extern void function_name(void);
    #endif /* BSP_CFG_RTOS_USED */

    #define R_BSP_PRAGMA_STATIC_INTERRUPT_FUNCTION(function_name)         R_BSP_PRAGMA(interrupt function_name)\
                                                                          static void function_name(void);

    #define R_BSP_ATTRIB_INTERRUPT                                        extern /* only this one because of no corresponding keyword */

    #if BSP_CFG_RTOS_USED == 4    /* Renesas RI600V4 & RI600PX */
    #define R_BSP_ATTRIB_STATIC_INTERRUPT                                 
    #else /* BSP_CFG_RTOS_USED !=4 */
    #define R_BSP_ATTRIB_STATIC_INTERRUPT                                 static /* only this one because of no corresponding keyword */
    #endif /* BSP_CFG_RTOS_USED */

    /* Fast */
    #define R_BSP_PRAGMA_FAST_INTERRUPT(function_name, vector)            R_BSP_PRAGMA(interrupt function_name(vect=vector, fint))\
                                                                          extern void function_name(void);
    #define R_BSP_PRAGMA_STATIC_FAST_INTERRUPT(function_name, vector)     R_BSP_PRAGMA(interrupt function_name(vect=vector, fint))\
                                                                          static void function_name(void);

    #define R_BSP_PRAGMA_FAST_INTERRUPT_FUNCTION(function_name)           R_BSP_PRAGMA(interrupt function_name(fint))\
                                                                          extern void function_name(void);
    #define R_BSP_PRAGMA_STATIC_FAST_INTERRUPT_FUNCTION(function_name)    R_BSP_PRAGMA(interrupt function_name(fint))\
                                                                          static void function_name(void);

    #define R_BSP_ATTRIB_FAST_INTERRUPT                                   extern /* only this one because of no corresponding keyword */
    #define R_BSP_ATTRIB_STATIC_FAST_INTERRUPT                            static /* only this one because of no corresponding keyword */

    /* Default */
    #if BSP_CFG_RTOS_USED == 4    /* Renesas RI600V4 & RI600PX */
    #define R_BSP_PRAGMA_INTERRUPT_DEFAULT(function_name)                 extern void function_name(void);

    #define R_BSP_PRAGMA_STATIC_INTERRUPT_DEFAULT(function_name)          void function_name(void);
    #else /* BSP_CFG_RTOS_USED != 4 */
    #define R_BSP_PRAGMA_INTERRUPT_DEFAULT(function_name)                 R_BSP_PRAGMA(interrupt function_name)\
                                                                          extern void function_name(void);

    #define R_BSP_PRAGMA_STATIC_INTERRUPT_DEFAULT(function_name)          R_BSP_PRAGMA(interrupt function_name)\
                                                                          static void function_name(void);
    #endif /* BSP_CFG_RTOS_USED */

     

    #elif defined(__GNUC__)

    /* Standard */
    #define R_BSP_PRAGMA_INTERRUPT(function_name, vector)                 extern void function_name(void) __attribute__((interrupt(R_BSP_SECNAME_INTVECTTBL, vector)));
    #define R_BSP_PRAGMA_STATIC_INTERRUPT(function_name, vector)          static void function_name(void) __attribute__((interrupt(R_BSP_SECNAME_INTVECTTBL, vector), used));

    #define R_BSP_PRAGMA_INTERRUPT_FUNCTION(function_name)                extern void function_name(void) __attribute__((interrupt));
    #define R_BSP_PRAGMA_STATIC_INTERRUPT_FUNCTION(function_name)         static void function_name(void) __attribute__((interrupt, used));

    #define R_BSP_ATTRIB_INTERRUPT                                        extern /* only this one because __attribute__((interrupt)) prevents GNURX from generating vector */
    #define R_BSP_ATTRIB_STATIC_INTERRUPT                                 static /* only this one because __attribute__((interrupt, used)) prevents GNURX from generating vector */

    /* Fast */
    #define R_BSP_PRAGMA_FAST_INTERRUPT(function_name, vector)            extern void function_name(void) __attribute__((interrupt(R_BSP_SECNAME_INTVECTTBL, vector))) \
                                                                                                          __attribute__((fast_interrupt));
    #define R_BSP_PRAGMA_STATIC_FAST_INTERRUPT(function_name, vector)     static void function_name(void) __attribute__((interrupt(R_BSP_SECNAME_INTVECTTBL, vector), used)) \
                                                                                                          __attribute__((fast_interrupt, used));

    #define R_BSP_PRAGMA_FAST_INTERRUPT_FUNCTION(function_name)           extern void function_name(void) __attribute__((fast_interrupt));
    #define R_BSP_PRAGMA_STATIC_FAST_INTERRUPT_FUNCTION(function_name)    static void function_name(void) __attribute__((fast_interrupt, used));

    #define R_BSP_ATTRIB_FAST_INTERRUPT                                   extern /* __attribute__((interrupt(fast))) Not necessary,
                                                                                    but Don't forget a R_BSP_PRAGMA_FAST_INTERRUPT() declaration */
    #define R_BSP_ATTRIB_STATIC_FAST_INTERRUPT                            static /* __attribute__((interrupt(fast)), used) Not necessary,
                                                                                    but Don't forget a R_BSP_PRAGMA_STATIC_FAST_INTERRUPT() declaration */

    /* Default */
    #define R_BSP_PRAGMA_INTERRUPT_DEFAULT(function_name)                 extern void function_name(void) __attribute__((interrupt(R_BSP_SECNAME_INTVECTTBL, "$default")));
    #define R_BSP_PRAGMA_STATIC_INTERRUPT_DEFAULT(function_name)          static void function_name(void) __attribute__((interrupt(R_BSP_SECNAME_INTVECTTBL, "$default"), used));

     

    #elif defined(__ICCRX__)

    /* Standard */
    #define R_BSP_PRAGMA_INTERRUPT(function_name, vect)                   R_BSP_PRAGMA(vector=vect)\
                                                                          extern __interrupt void function_name(void);
    #define R_BSP_PRAGMA_STATIC_INTERRUPT(function_name, vect)            R_BSP_PRAGMA(vector=vect)\
                                                                          static __interrupt void function_name(void);

    #define R_BSP_PRAGMA_INTERRUPT_FUNCTION(function_name)                extern __interrupt void function_name(void);
    #define R_BSP_PRAGMA_STATIC_INTERRUPT_FUNCTION(function_name)         static __interrupt void function_name(void);

    #define R_BSP_ATTRIB_INTERRUPT                                        extern __interrupt /* ICCRX requires __interrupt not only at a function declaration but also at a function definition */
    #define R_BSP_ATTRIB_STATIC_INTERRUPT                                 static __interrupt /* ICCRX requires __interrupt not only at a function declaration but also at a function definition */

    /* Fast */
    #define R_BSP_PRAGMA_FAST_INTERRUPT(function_name, vect)              R_BSP_PRAGMA(vector=vect)\
                                                                          extern __fast_interrupt void function_name(void);
    #define R_BSP_PRAGMA_STATIC_FAST_INTERRUPT(function_name, vect)       R_BSP_PRAGMA(vector=vect)\
                                                                          static __fast_interrupt void function_name(void);

    #define R_BSP_PRAGMA_FAST_INTERRUPT_FUNCTION(function_name)           extern __fast_interrupt void function_name(void);
    #define R_BSP_PRAGMA_STATIC_FAST_INTERRUPT_FUNCTION(function_name)    static __fast_interrupt void function_name(void);

    #define R_BSP_ATTRIB_FAST_INTERRUPT                                   extern __fast_interrupt /* ICCRX requires __interrupt not only at a function declaration but also at a function definition */
    #define R_BSP_ATTRIB_STATIC_FAST_INTERRUPT                            static __fast_interrupt /* ICCRX requires __interrupt not only at a function declaration but also at a function definition */

    /* Default */
    #define R_BSP_PRAGMA_INTERRUPT_DEFAULT(function_name)                 extern __interrupt void function_name(void);
    #define R_BSP_PRAGMA_STATIC_INTERRUPT_DEFAULT(function_name)          static __interrupt void function_name(void);

    #endif