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です。

    FIT/CGの割り込み処理は、関数先頭で多重割り込み許可を設定される、ということを想定されて設計とか設計レビューとかされていないと思いますので、無理矢理そういうことをすると誤動作するリスクはもちろんあると思っています。

    (1) CGコンポーネントの場合

    割り込み処理のコード全体を容易に見渡せますので、そういうことをしたら誤動作するかどうかも気付きやすいと思います。他方で、たとえ通信コンポーネントなどでも、1チャンネルずつ独立したソースになっていて、チャンネル間で何かしらの管理データを共有する、ということもありませんので、もともとトラブルを起こす可能性は少なそうに思われます。(ただ、全てのCGコンポーネントを触ったわけでは無いので、たぶん共有は無さそう、というところですが。)

    (2) FITモジュールの場合

    1つの通信モジュール(のソース)で複数のチャンネルをサポートしていたりしますので、チャンネル間で何かしらの管理データを共有しているかも知れず、チャンネル間で割り込み優先度を変えたりすると、そういったデータの操作が破綻して、トラブルを起こす可能性は想定されることです。他方で、チャンネル間で割り込み優先度を変えたりしなければ、関数先頭で多重割り込みを許可するということを無理矢理やってもトラブルを起こす可能性は少なそうに思われます。こちらは、割り込み処理のコード全体を容易に見渡せるというわけでも無く、それなりに気合を入れてソースを追ってからでないと、誤動作してしまうのかどうか分からないと思います。

  • こんにちは。NoMaYです。

    CGコンポーネントでユーザ記述部だけで割り込み関数先頭での多重割り込み許可を設定する小細工が思い浮かんだので書いておきます。


    CC-RX : コンパイルオプションに -save_acc (割り込み関数でのアキュムレータの退避/復帰を行う)を指定

    ソース例: Config_RIIC0_user.c

    /* Start user code for global. Do not edit comment generated here */

    #undef  VECT
    #define VECT( x , y ) _VECT( _ ## x ## _ ## y ), enable

    /* End user code. Do not edit comment generated here */

     

    #if FAST_INTERRUPT_VECTOR == VECT_RIIC0_TXI0
    #pragma interrupt r_Config_RIIC0_transmit_interrupt(vect=VECT(RIIC0,TXI0),fint)
    #else
    #pragma interrupt r_Config_RIIC0_transmit_interrupt(vect=VECT(RIIC0,TXI0))
    #endif
    static void r_Config_RIIC0_transmit_interrupt(void)
    {
        …途中省略…
    }

     

    #if FAST_INTERRUPT_VECTOR == VECT_RIIC0_RXI0
    #pragma interrupt r_Config_RIIC0_receive_interrupt(vect=VECT(RIIC0,RXI0),fint)
    #else
    #pragma interrupt r_Config_RIIC0_receive_interrupt(vect=VECT(RIIC0,RXI0))
    #endif
    static void r_Config_RIIC0_receive_interrupt(void)
    {
        …途中省略…
    }

     
    リストファイル: アキュムレータが使われない/値が壊れないことを認識してアキュムレータの退避/復帰を省略していますね

    00000001         __$r_Config_RIIC0_transmit_interrupt:
                            .STACK  __$r_Config_RIIC0_transmit_interrupt=24
                            .RVECTOR    53,__$r_Config_RIIC0_transmit_interrupt
    00000001 7FA8           SETPSW I
    00000003 6E14           PUSHM R1-R4

                            …途中省略…

    00000048 6F14           POPM R1-R4
    0000004A 7F95           RTE
                            …途中省略…
    00000061 6F14           POPM R1-R4
    00000063 7F95           RTE
                            …途中省略…
    00000082 6F14           POPM R1-R4
    00000084 7F95           RTE
                            …途中省略…
    000000B2 6F14           POPM R1-R4
    000000B4 7F95           RTE
                            …途中省略…
    000000D8 6F14           POPM R1-R4
    000000DA 7F95           RTE
                            …途中省略…
    000000F4 6F14           POPM R1-R4
    000000F6 7F95           RTE
                            …途中省略…
    00000112 6F14           POPM R1-R4
    00000114 7F95           RTE

     

    00000156         __$r_Config_RIIC0_receive_interrupt:
                            .STACK  __$r_Config_RIIC0_receive_interrupt=32
                            .RVECTOR    52,__$r_Config_RIIC0_receive_interrupt
    00000156 7FA8           SETPSW I
    00000158 6E15           PUSHM R1-R5
                            …1行省略…
    00000160 6040           SUB #04H, R0

                            …途中省略…

    0000025D 6240           ADD #04H, R0
    0000025F 6F15           POPM R1-R5
    00000261 7F95           RTE

     

    ICCRX : コンパイルオプションに --save_acc (割り込み関数でアキュムレータの退避/復帰を行う)を指定

    ソース例: Config_RIIC0_user.c

    /* Start user code for global. Do not edit comment generated here */

    #define __interrupt __interrupt __nested

    /* End user code. Do not edit comment generated here */

     

    #pragma vector = VECT_RIIC0_TXI0
    #if FAST_INTERRUPT_VECTOR == VECT_RIIC0_TXI0
    __fast_interrupt static void r_Config_RIIC0_transmit_interrupt(void)
    #else
    __interrupt static void r_Config_RIIC0_transmit_interrupt(void)
    #endif
    {
        …途中省略…
    }

     

    #pragma vector = VECT_RIIC0_RXI0
    #if FAST_INTERRUPT_VECTOR == VECT_RIIC0_RXI0
    __fast_interrupt static void r_Config_RIIC0_receive_interrupt(void)
    #else
    __interrupt static void r_Config_RIIC0_receive_interrupt(void)
    #endif
    {
        …途中省略…
    }

     
    リストファイル: そもそもバグによりアキュムレータの退避/復帰を行うコードが生成されないみたいですね

       \                                 In section .text, align 1, keep-with-next
       \                     ___interrupt_53:
       \   000000 7F A8        SETPSW    I
       \   000002 7E AE        PUSH.L    R14
       \   000004 6E 16        PUSHM     R1-R6

                               …途中省略…

       \   0000FD 6F 16        POPM      R1-R6
       \   0000FF 7E BE        POP       R14
       \   000101 7F 95        RTE

     

       \                                 In section .text, align 1, keep-with-next
       \                     ___interrupt_52:
       \   000000 7F A8        SETPSW    I
       \   000002 6E EF        PUSHM     R14-R15
       \   000004 6E 16        PUSHM     R1-R6
       \   000006 60 40        SUB       #0x4,SP

                               …途中省略…

       \   000093 62 40        ADD       #0x4,SP
       \   000095 6F 16        POPM      R1-R6
       \   000097 6F EF        POPM      R14-R15
       \   000099 7F 95        RTE

     

    GNURX : コンパイルオプションに -msave-acc-in-interrupts (割り込み関数でアキュムレータの退避/復帰を行う)を指定

    ソース例: Config_RIIC0_user.c

    /* Start user code for global. Do not edit comment generated here */

    void r_Config_RIIC0_transmit_interrupt(void) __attribute__ ((naked));
    void r_Config_RIIC0_transmit_interrupt(void)
    {
        __asm volatile ("SETPSW I");
        __asm volatile ("BRA.S __r_Config_RIIC0_transmit_interrupt"); /* BRA.S is not necessary but it is intended for the safe. */
    }
    void _r_Config_RIIC0_transmit_interrupt(void) __attribute__ ((interrupt, section(".text.r_Config_RIIC0_transmit_interrupt")));
    #define r_Config_RIIC0_transmit_interrupt _r_Config_RIIC0_transmit_interrupt

    void r_Config_RIIC0_receive_interrupt(void) __attribute__ ((naked));
    void r_Config_RIIC0_receive_interrupt(void)
    {
        __asm volatile ("SETPSW I");
        __asm volatile ("BRA.S __r_Config_RIIC0_receive_interrupt"); /* BRA.S is not necessary but it is intended for the safe. */
    }
    void _r_Config_RIIC0_receive_interrupt(void) __attribute__ ((interrupt, section(".text.r_Config_RIIC0_receive_interrupt")));
    #define r_Config_RIIC0_receive_interrupt _r_Config_RIIC0_receive_interrupt

    /* End user code. Do not edit comment generated here */

     

    void r_Config_RIIC0_transmit_interrupt(void)
    {
        …途中省略…
    }

     

    void r_Config_RIIC0_receive_interrupt(void)
    {
        …途中省略…
    }

     
    リストファイル:

       4                     .section .text.r_Config_RIIC0_transmit_interrupt,"ax",@progbits
       5                     .global _r_Config_RIIC0_transmit_interrupt
       7                 _r_Config_RIIC0_transmit_interrupt:
      11                     .global $tableentry$53$.rvectors
      12                 $tableentry$53$.rvectors:
      13                     ; Note: Interrupt Handler
      14                     ; Note: Naked Function
      17 0000 7F A8          SETPSW I
      21 0002 08             BRA.S __r_Config_RIIC0_transmit_interrupt

      27                     .global __r_Config_RIIC0_transmit_interrupt
      29                 __r_Config_RIIC0_transmit_interrupt:
      33 0003 6E 15          pushm   r1-r5
      35 0005 FD 1F 11       mvfaclo #0, A0, r1
      36 0008 FD 1F 02       mvfachi r2
      37 000b 6E 12          pushm   r1-r2
      38 000d FD 1F 31       mvfacgu #0, A0, r1
      39 0010 FD 1F 92       mvfaclo #0, A1, r2
      40 0013 6E 12          pushm   r1-r2
      41 0015 FD 1F 81       mvfachi #0, A1, r1
      42 0018 FD 1F B2       mvfacgu #0, A1, r2
      43 001b 6E 12          pushm   r1-r2

                             …途中省略…

      59 0030 6F 12          popm    r1-r2
      60 0032 FD 17 81       mvtachi r1, A1
      61 0035 FD 17 B2       mvtacgu r2, A1
      62 0038 6F 12          popm    r1-r2
      63 003a FD 17 31       mvtacgu r1, A0
      *** 003d FD 17 92       mvtaclo r2, A1
      65 0040 6F 12          popm    r1-r2
      66 0042 FD 17 11       mvtaclo r1
      67 0045 FD 17 02       mvtachi r2
      68 0048 6F 15          popm    r1-r5
      69 004a 7F 95          rte
                             …途中省略…
     173 00e7 6F 12          popm    r1-r2
     174 00e9 FD 17 81       mvtachi r1, A1
     175 00ec FD 17 B2       mvtacgu r2, A1
     176 00ef 6F 12          popm    r1-r2
     177 00f1 FD 17 31       mvtacgu r1, A0
     178 00f4 FD 17 92       mvtaclo r2, A1
     179 00f7 6F 12          popm    r1-r2
     180 00f9 FD 17 11       mvtaclo r1
     181 00fc FD 17 02       mvtachi r2
     182 00ff 6F 15          popm    r1-r5
     183 0101 7F 95          rte
                             …途中省略…
     213 0133 6F 12          popm    r1-r2
     214 0135 FD 17 81       mvtachi r1, A1
     215 0138 FD 17 B2       mvtacgu r2, A1
     216 013b 6F 12          popm    r1-r2
     217 013d FD 17 31       mvtacgu r1, A0
     218 0140 FD 17 92       mvtaclo r2, A1
     219 0143 6F 12          popm    r1-r2
     220 0145 FD 17 11       mvtaclo r1
     221 0148 FD 17 02       mvtachi r2
     222 014b 6F 15          popm    r1-r5
     223 014d 7F 95          rte

     

     271                     .section .text.r_Config_RIIC0_receive_interrupt,"ax",@progbits
     272                     .global _r_Config_RIIC0_receive_interrupt
     274                 _r_Config_RIIC0_receive_interrupt:
     277                     .global $tableentry$52$.rvectors
     278                 $tableentry$52$.rvectors:
     279                     ; Note: Interrupt Handler
     280                     ; Note: Naked Function
     283 0000 7F A8          SETPSW I
     287 0002 08             BRA.S __r_Config_RIIC0_receive_interrupt

     293                     .global __r_Config_RIIC0_receive_interrupt
     295                 __r_Config_RIIC0_receive_interrupt:
     298                     ; Note: Interrupt Handler
     299 0003 6E EF          pushm   r14-r15
     301 0005 6E 15          pushm   r1-r5
     303 0007 FD 1F 11       mvfaclo #0, A0, r1
     304 000a FD 1F 02       mvfachi r2
     305 000d 7E A1          push.l  r1
     306 000f 7E A2          push.l  r2
     307 0011 FD 1F 31       mvfacgu #0, A0, r1
     308 0014 FD 1F 92       mvfaclo #0, A1, r2
     309 0017 7E A1          push.l  r1
     310 0019 7E A2          push.l  r2
     311 001b FD 1F 81       mvfachi #0, A1, r1
     312 001e FD 1F B2       mvfacgu #0, A1, r2
     313 0021 7E A1          push.l  r1
     314 0023 7E A2          push.l  r2
     315 0025 60 40          sub #4, r0

                             …途中省略…

     378 0070 62 40          add #4, r0
     379 0072 7E B2          pop r2
     380 0074 7E B1          pop r1
     381 0076 FD 17 81       mvtachi r1, A1
     382 0079 FD 17 B2       mvtacgu r2, A1
     383 007c 7E B2          pop r2
     384 007e 7E B1          pop r1
     385 0080 FD 17 31       mvtacgu r1, A0
     386 0083 FD 17 92       mvtaclo r2, A1
     387 0086 7E B2          pop r2
     388 0088 7E B1          pop r1
     389 008a FD 17 11       mvtaclo r1
     390 008d FD 17 02       mvtachi r2
     391 0090 6F 15          popm    r1-r5
     392 0092 6F EF          popm    r14-r15
     393 0094 7F 95          rte

     

  • NoMay さんこんにちは。

    今回の話題とは少し違いますが、「多重割り込み」について思うところがあります。

    そもそも、多重割り込みが必要なケースは、どんな場合があるでしょうか?

    大抵は、割り込み内から行う処理は、最小限にして、直ぐに割り込みを抜けるようにするので、割り込み内で、長時間処理を行う必要性がある場合は限られるのでは無いでしょうか?

    ※ハードウェアーのフラグが変化するまで待機するとかは論外と思います。

    少なくとも、SCI、I2C、SPI、A/D変換、どれも、多重割り込みが必要なケースを思い浮かびません。

    RXマイコンのペリフェラル系は、殆どがその事に留意して設計されており、割り込み内では、単純にレジスターを読み込んでバッファーにストアするだけで大抵は完了します。

    もちろん、多重割り込みが全く必要無いという事にはなりません。

    また、割り込み内で時間がかかりそうな処理があるなら、少し工夫すれば、追い出してメイン側で行う事は出来ると思います。

    多重割り込みを可能にする方法を提供する事は重要ですが、割り込み内処理が短く、必要性が薄いのなら、プロファイルとして、「多重割り込み不可」とすれば良いように思います。

    自分は、多重割り込みを必要とするケースはかなり低いと考えています。

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

    リプライありがとうございます。多重割り込みの小細工の件は、このスレッドの主題に因るところが大きいです。実は、私はといえば、たとえ10ms掛かるような割り込み処理があるプログラム(かつ多重割り込みさえ使っていないもの)でも、業務発注元からの要求仕様を満たしつつ、半年とか1年とか連続稼動するプログラムであれば、そういうのでも構わないと思っていたりします。(もっとも、それで済むようなプログラム開発業務はとても稀な業務だとは思いますけれども。)

    その一方で、このスレッドでは、私は、こんな風に考えるようになっています。(10クロックは寧ろ15クロックとすべき、とか、20クロックは寧ろ30クロックとすべき、とか、突っ込みはあるでしょうけれども。)


    (1) レジスタ一括退避機能を使用して割り込み応答性を改善出来るといっても、5クロックとか、10クロックとか、20クロックとか、ぐらいである

    (1') アキュムレータを使わないようなプログラムでは、5クロックとか、10クロックとか、そんなぐらいである

    (1'') 10クロックとか改善されるケースを想像してみると、そもそも大量にレジスタを使う複雑な処理なのだから、応答性だけ改善する意義は少ないかと


    (2) 他方で、割り込み処理をシンプルにすれば良いといっても、さすがに、多くの割り込み処理が数クロックで終わる、ことも無いと思う

    (2') カウンタをインクリメントする程度の処理なら、それくらいでしょうけれども

    (2'') 例えば、昨日の投稿で例に使ったConfig_RIIC0_user.cの割り込み処理も、下の方に添付したように、数クロックで終わるものでも無いです

    (2''') ちなみに、サブルーチン呼び出しのオーバーヘッドは3+5=8クロックだったり、内蔵周辺I/Oレジスタアクセスには数クロックウェイトが入ったりします


    (3) 例えば100クロックとか多重割り込み不可の期間があっても動作し続けるプログラムなら、レジスタ一括退避機能で5クロック改善する必要も無いかと

    (3') もっとも、割り込み発生タイミングが重ならないことが保証されているなら、そこまでは言いませんけれども


    (4) 例えば、hirakuni45さんの文面を借りれば、そもそも私は、割り込み応答性を5クロック改善することが必須であるようなケースが思い浮かびません

    (4') ましてや、100クロックとか多重割り込み不可の期間が存在していても構わないのに、かつ、5クロック改善することが必須であるとか、想像出来ません

    (4'') もっとも、割り込み発生タイミングが重ならないことが保証されているなら、そこまでは言いませんけれども


    (5) 逆に、レジスタ一括退避機能で5クロック改善することが必須であるような案件では、100クロックとか多重割り込み不可の期間は良くないのでは

    (5') 例えば、再度、hirakuni45さんの文面を借りれば、レジスタ一括退避機能で5クロック改善することが必須であるような案件というのは、「もちろん、多重割り込みが全く必要無いという事にはなりません。」ということに該当する案件なのではないかなと思うのです


    補足:

    上の文を読み返していて、説明不足だと思ったのですが、以下の説明が上の文では欠落しているような気がしました。


    (A) 高い割り込み優先度の自前の割り込み処理でレジスタ一括退避機能で割り込み応答性を改善しようとしている、ということを想定している

    (A') FIT/CGの出来合いの割り込み処理については割り込み優先度を低く設定している、ということを想定している

    (A'') 決して、低い割り込み優先度を設定しているFIT/CGの出来合いの割り込み処理にて、レジスタ一括退避機能を使おうとしているのでは無いです


    (B) 一旦、低い割り込み優先度の割り込み処理へ入ってしまうと、多重割り込み不可では、高い割り込み優先度であっても割り込みは受け付けられない

    (B') 低い割り込み優先度の割り込み処理が終わるまで、多重割り込み不可では、高い割り込み優先度の割り込みの受け付けは遅延してしまう

    (B'') 多重割り込み不可というのは、そういう遅延が発生する状況(そういう遅延が発生してしまうかも知れない可能性がある状況)のことである


    以下、昨日の投稿で例に使ったConfig_RIIC0_user.cの割り込み処理の全体のソース(CGコンポーネントのGNURX版)です。(if文で大きく排他的なブロックに分けられた構造ですので、ぱっと見た印象より、割り込み処理の正味の実行クロック数は少ないですけれども。)

    void r_Config_RIIC0_transmit_interrupt(void)
    {
        if (_0D_IIC_MASTER_TRANSMIT == g_riic0_mode_flag)
        {
            if (_01_IIC_MASTER_SENDS_ADR_7_W == g_riic0_state)
            {
                RIIC0.ICDRT = (uint8_t)(g_riic0_slave_address << 1U);
                g_riic0_state = _05_IIC_MASTER_SENDS_DATA;
            }
            else if (_02_IIC_MASTER_SENDS_ADR_10A_W == g_riic0_state)
            {
                RIIC0.ICDRT = (uint8_t)(((g_riic0_slave_address & 0x0300U) >> 7U) | 0x00F0U);
                g_riic0_state = _04_IIC_MASTER_SENDS_ADR_10B;
            }
            else if (_04_IIC_MASTER_SENDS_ADR_10B == g_riic0_state)
            {
                RIIC0.ICDRT = (uint8_t)(g_riic0_slave_address & 0x00FFU);
                g_riic0_state = _05_IIC_MASTER_SENDS_DATA;
            }
            else if (_05_IIC_MASTER_SENDS_DATA == g_riic0_state)
            {
                if (0U < g_riic0_tx_count)
                {
                    RIIC0.ICDRT = *gp_riic0_tx_address;
                    gp_riic0_tx_address++;
                    g_riic0_tx_count--;
                }
                else
                {
                    g_riic0_state = _06_IIC_MASTER_SENDS_END;
                }
            }
            else
            {
                 /* Do nothing */
            }
        }
        else if (_0C_IIC_MASTER_RECEIVE == g_riic0_mode_flag)
        {
            if (_00_IIC_MASTER_SENDS_ADR_7_R == g_riic0_state)
            {
                RIIC0.ICDRT = (uint8_t)((g_riic0_slave_address << 1U) | 0x0001U);
                g_riic0_state = _08_IIC_MASTER_RECEIVES_START;
            }
            else if (_02_IIC_MASTER_SENDS_ADR_10A_W == g_riic0_state)
            {
                RIIC0.ICDRT = (uint8_t)(((g_riic0_slave_address & 0x0300U) >> 7U) | 0x00F0U);
                g_riic0_state = _04_IIC_MASTER_SENDS_ADR_10B;
            }
            else if (_04_IIC_MASTER_SENDS_ADR_10B == g_riic0_state)
            {
                RIIC0.ICDRT = (uint8_t)(g_riic0_slave_address & 0x00FFU);
                g_riic0_state = _0E_IIC_MASTER_RECEIVES_RESTART;
            }
            else if (_03_IIC_MASTER_SENDS_ADR_10A_R == g_riic0_state)
            {
                RIIC0.ICDRT = (uint8_t)(((g_riic0_slave_address & 0x0300U) >> 7U) | 0x00F1U);
                g_riic0_state = _08_IIC_MASTER_RECEIVES_START;
            }
            else
            {
                 /* Do nothing */
            }
        }
        else
        {
             /* Do nothing */
        }
    }

     

    void r_Config_RIIC0_receive_interrupt(void)
    {
        volatile uint8_t dummy;

        if (_08_IIC_MASTER_RECEIVES_START == g_riic0_state)
        {
            if ((2U == g_riic0_rx_length) || (1U == g_riic0_rx_length))
            {
                RIIC0.ICMR3.BIT.WAIT = 1U;
            }

            if (1U == g_riic0_rx_length)
            {
                RIIC0.ICMR3.BIT.ACKWP = 1U;
                RIIC0.ICMR3.BIT.ACKBT = 1U;
            }

            /* Dummy read to release SCL */
            dummy = RIIC0.ICDRR;

            g_riic0_state = _09_IIC_MASTER_RECEIVES_DATA;

            if (1U == g_riic0_rx_length)
            {
                g_riic0_state = _0A_IIC_MASTER_RECEIVES_STOPPING;
            }
        }
        else if (_09_IIC_MASTER_RECEIVES_DATA == g_riic0_state)
        {
            if (g_riic0_rx_count < g_riic0_rx_length)
            {
                if (g_riic0_rx_count == (g_riic0_rx_length - 3))
                {
                    RIIC0.ICMR3.BIT.WAIT = 1U;

                    *gp_riic0_rx_address = RIIC0.ICDRR;
                    gp_riic0_rx_address++;
                    g_riic0_rx_count++;
                }
                else if (g_riic0_rx_count == (g_riic0_rx_length - 2))
                {
                    RIIC0.ICMR3.BIT.ACKWP = 1U;
                    RIIC0.ICMR3.BIT.ACKBT = 1U;

                    *gp_riic0_rx_address = RIIC0.ICDRR;
                    gp_riic0_rx_address++;
                    g_riic0_rx_count++;

                    g_riic0_state = _0A_IIC_MASTER_RECEIVES_STOPPING;
                }
                else
                {
                    *gp_riic0_rx_address = RIIC0.ICDRR;
                    gp_riic0_rx_address++;
                    g_riic0_rx_count++;
                }
            }
        }
        else if (_0A_IIC_MASTER_RECEIVES_STOPPING == g_riic0_state)
        {
            RIIC0.ICSR2.BIT.STOP = 0U;
            RIIC0.ICCR2.BIT.SP = 1U;

            *gp_riic0_rx_address = RIIC0.ICDRR;
            gp_riic0_rx_address++;
            g_riic0_rx_count++;

            RIIC0.ICMR3.BIT.WAIT = 0U;
            g_riic0_state = _0B_IIC_MASTER_RECEIVES_STOP;
        }
        else
        {
             /* Do nothing */
        }
    }

     
    [追記]

    逆に、ぱっと見た印象より、ずっと長い割り込み禁止となっていると思われる割り込み関数として気になっているのが、BSPモジュールの以下の割り込み関数です。(同様なif文の塊のような構造の割り込み関数は他にもあります。) if文の比較処理の1回あたりが例えば5クロックぐらいしか掛からなかったとしても、if文を20個も30個も並べたら100クロックだの150クロックだの掛かってしまうよね、と思われるのです。

    R_BSP_ATTRIB_STATIC_INTERRUPT void group_bl0_handler_isr (void)
    {
        /* BL0 IS1 */
        if (1 == ICU.GRPBL0.BIT.IS1)
        {
            /* BSP_INT_SRC_BL0_SCI0_ERI0 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI0_ERI0, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS0 */
        if (1 == ICU.GRPBL0.BIT.IS0)
        {
            /* BSP_INT_SRC_BL0_SCI0_TEI0 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI0_TEI0, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS3 */
        if (1 == ICU.GRPBL0.BIT.IS3)
        {
            /* BSP_INT_SRC_BL0_SCI1_ERI1 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI1_ERI1, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS2 */
        if (1 == ICU.GRPBL0.BIT.IS2)
        {
            /* BSP_INT_SRC_BL0_SCI1_TEI1 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI1_TEI1, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS5 */
        if (1 == ICU.GRPBL0.BIT.IS5)
        {
            /* BSP_INT_SRC_BL0_SCI2_ERI2 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI2_ERI2, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS4 */
        if (1 == ICU.GRPBL0.BIT.IS4)
        {
            /* BSP_INT_SRC_BL0_SCI2_TEI2 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI2_TEI2, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS7 */
        if (1 == ICU.GRPBL0.BIT.IS7)
        {
            /* BSP_INT_SRC_BL0_SCI3_ERI3 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI3_ERI3, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS6 */
        if (1 == ICU.GRPBL0.BIT.IS6)
        {
            /* BSP_INT_SRC_BL0_SCI3_TEI3 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI3_TEI3, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS9 */
        if (1 == ICU.GRPBL0.BIT.IS9)
        {
            /* BSP_INT_SRC_BL0_SCI4_ERI4 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI4_ERI4, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS8 */
        if (1 == ICU.GRPBL0.BIT.IS8)
        {
            /* BSP_INT_SRC_BL0_SCI4_TEI4 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI4_TEI4, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS11 */
        if (1 == ICU.GRPBL0.BIT.IS11)
        {
            /* BSP_INT_SRC_BL0_SCI5_ERI5 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI5_ERI5, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS10 */
        if (1 == ICU.GRPBL0.BIT.IS10)
        {
            /* BSP_INT_SRC_BL0_SCI5_TEI5 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI5_TEI5, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS13 */
        if (1 == ICU.GRPBL0.BIT.IS13)
        {
            /* BSP_INT_SRC_BL0_SCI6_ERI6 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI6_ERI6, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS12 */
        if (1 == ICU.GRPBL0.BIT.IS12)
        {
            /* BSP_INT_SRC_BL0_SCI6_TEI6 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI6_TEI6, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS17 */
        if (1 == ICU.GRPBL0.BIT.IS17)
        {
            /* BSP_INT_SRC_BL0_SCI12_ERI12 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI12_ERI12, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS16 */
        if (1 == ICU.GRPBL0.BIT.IS16)
        {
            /* BSP_INT_SRC_BL0_SCI12_TEI12 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI12_TEI12, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS18 */
        if (1 == ICU.GRPBL0.BIT.IS18)
        {
            /* BSP_INT_SRC_BL0_SCI12_SCIX0 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI12_SCIX0, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS19 */
        if (1 == ICU.GRPBL0.BIT.IS19)
        {
            /* BSP_INT_SRC_BL0_SCI12_SCIX1 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI12_SCIX1, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS20 */
        if (1 == ICU.GRPBL0.BIT.IS20)
        {
            /* BSP_INT_SRC_BL0_SCI12_SCIX2 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI12_SCIX2, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS21 */
        if (1 == ICU.GRPBL0.BIT.IS21)
        {
            /* BSP_INT_SRC_BL0_SCI12_SCIX3 */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI12_SCIX3, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS24 */
        if (1 == ICU.GRPBL0.BIT.IS24)
        {
            /* BSP_INT_SRC_BL0_QSPI_QSPSSLI */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_QSPI_QSPSSLI, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS26 */
        if (1 == ICU.GRPBL0.BIT.IS26)
        {
            /* BSP_INT_SRC_BL0_CAC_FERRI */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_CAC_FERRI, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS27 */
        if (1 == ICU.GRPBL0.BIT.IS27)
        {
            /* BSP_INT_SRC_BL0_CAC_MENDI */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_CAC_MENDI, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS28 */
        if (1 == ICU.GRPBL0.BIT.IS28)
        {
            /* BSP_INT_SRC_BL0_CAC_OVFI */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_CAC_OVFI, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS29 */
        if (1 == ICU.GRPBL0.BIT.IS29)
        {
            /* BSP_INT_SRC_BL0_DOC_DOPCI */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_DOC_DOPCI, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS31 */
        if (1 == ICU.GRPBL0.BIT.IS31)
        {
            /* BSP_INT_SRC_BL0_PDC_PCERI */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_PDC_PCERI, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }

        /* BL0 IS30 */
        if (1 == ICU.GRPBL0.BIT.IS30)
        {
            /* BSP_INT_SRC_BL0_PDC_PCFEI */
            R_BSP_InterruptControl(BSP_INT_SRC_BL0_PDC_PCFEI, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR);
        }
    } /* End of function group_bl0_handler_isr() */

     

  • シェルティさん、こんにちは。NoMaYです。

    別スレッドで頂いていた以下のリプライは、こちらのスレッドのものでしょうかね。リプライありがとうございました。

    community-ja.renesas.com/cafe_rene/forums-groups/tools/f/forum21/9581/gcc-for-renesas-rx-gnurx-dcmr/46877#46877

    シェルティです、こんにちは。

    ご連絡、解析ありがとうございます。こちらではRXv3コアのレジスタ一括退避機能をFreeRTOSカーネルで使ってみてどうなるかの検証を進めています。過去にNoMaYさんに実施いただいたプルリクエストなどを活用して、AWS本家と調整してみようと考えています。

    なお、「RXv3コアのレジスタ一括退避機能」そのものや「多重割込み」の是非についても考え方をまとめてみたいなと考えています。個人的にはNoMaYさんと似た感じの考えでいます。

    以上です


  • NoMaYさん

    シェルティです、こんにちは。

    はい。こちらのスレッドを指してのリプライでした。ありがとうございます。

    引き続きNoMaYさんやhirakuni45さんの書き込み等を参考にさせていただき、FreeRTOS公式のコードへのフィードバック方法の検討を進めてまいります。

    NoMaYさんとAmazon FreeRTOSの開発を一緒に始めたときはこちらシェルティひとりだったのですが、今は1個チームが組めるくらいに開発費が集まりスタンドアロンで動き始めました。ただまだまだこういった掲示板での活動やGitHubを使ってみたりなどの新しい取り組みを開始するには若いチームなので、進行速度は早くありません。AWS側の変化に追従するのに四苦八苦、といった状況ですね。とはいえ何とかいただいたフィードバックは公式に反映していくべく活動継続してまいります。Azure RTOS関連の開発も同じチームで推進しています。

    シェルティの方はというと、RTOS開発は開発チームに任せて、サンプルコードの提供方法のマイコン間の共通化や、社内ソフトウェア開発環境の整備(GitLab CI/CDを活用したマイコンソフトの評価の実機レベルでの自動化実現による品質・開発効率向上)などの活動に勤しんでおります。

    #さらに個人的にはグローバルなRTOSの整備が最低限できたから、そろそろ日本人としてITRONをまたやりたいなァ・・・などと妄想しています

    以上です

  • こんにちは。NoMaYです。

    以前に投稿した以下の件で思ったのですけれども、今のBSPモジュールには以下の定義がありますので、割り込み関数先頭で多重割り込みを許可した後、PSWのIPLフィールドの値を以下の定義の値に変更してやれば、FITモジュール相互間での多重割り込みは起きませんので、それなりにトラブルも無く運用出来そうな気がしました。(もっとも、同一のマクロで良いのかどうか吟味は必要かなぁ、とは思いますけれども。)

    r_bsp_config.h

    /* For some BSP functions, it is necessary to ensure that, while these functions are executing, interrupts from other 
       FIT modules do not occur. By controlling the IPL, these functions disable interrupts that are at or below the
       specified interrupt priority level.
       This macro sets the IPL. Range is 0x0 - 0xF.
       Please set this macro more than IPR for other FIT module interrupts.
       The default value is 0xF (maximum value).
       Don't change if there is no special processing with higher priority than all fit modules.
    */
    #define BSP_CFG_FIT_IPL_MAX                         (0xF)

     

    > FIT/CGの割り込み処理は、関数先頭で多重割り込み許可を設定される、ということを想定されて設計とか設計レビューとかされていないと思いますので、無理矢理そういうことをすると誤動作するリスクはもちろんあると思っています。

    > (1) CGコンポーネントの場合

    > 割り込み処理のコード全体を容易に見渡せますので、そういうことをしたら誤動作するかどうかも気付きやすいと思います。他方で、たとえ通信コンポーネントなどでも、1チャンネルずつ独立したソースになっていて、チャンネル間で何かしらの管理データを共有する、ということもありませんので、もともとトラブルを起こす可能性は少なそうに思われます。(ただ、全てのCGコンポーネントを触ったわけでは無いので、たぶん共有は無さそう、というところですが。)

    > (2) FITモジュールの場合

    > 1つの通信モジュール(のソース)で複数のチャンネルをサポートしていたりしますので、チャンネル間で何かしらの管理データを共有しているかも知れず、チャンネル間で割り込み優先度を変えたりすると、そういったデータの操作が破綻して、トラブルを起こす可能性は想定されることです。他方で、チャンネル間で割り込み優先度を変えたりしなければ、関数先頭で多重割り込みを許可するということを無理矢理やってもトラブルを起こす可能性は少なそうに思われます。こちらは、割り込み処理のコード全体を容易に見渡せるというわけでも無く、それなりに気合を入れてソースを追ってからでないと、誤動作してしまうのかどうか分からないと思います。

    [メモ]

    考察が必要な事項

    (1) 既に自前で、コールバック関数内で多重割り込み許可にして、FITモジュール相互間の多重割り込みを運用中のユーザ
    (2) うっかり多重割り込みの優先度設定を間違えて、発生した割り込みよりIPLの値を小さくしてしまうというトラブルの防止策

  • こんにちは。NoMaYです。

    割り込みは、割り込み許可状態だったとしても、割り込み要求が発生してすぐに割り込みルーチンへ飛ぶわけでは無いことを思い出し、ちょっと調べてみました。除算命令では命令実行に20クロックほど掛かるケースもあるようですね。命令実行が1クロックで終わる命令に比べ、その分、割り込みルーチンへ飛ぶのが遅れますね。なお、コンパイラには、命令実行に時間が掛かる命令(割り込みルーチンへ飛ぶのが遅れる命令)を使わないようにするコンパイルオプションもあります。ただ、そのようにした場合、割り込み応答性を低下させるリスクが減るメリットの代償として、プログラム処理時間が長くなるデメリットがありますけれども。(あと、PUSHM命令/POPM命令/RTSD命令も命令実行時間が長くなるケースがありますね。) [追記] 開平演算(√)命令も命令実行に時間が掛かる命令ですね。

    以下、ハードウェアマニュアルの画面コピーです。

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







    [追記]

    すみません、倍精度浮動小数点演算命令に関して載せ忘れましたので追加します。(あと、こちらも、除算命令の他に、DPUSHM命令/DPOPM命令も命令実行時間が長くなるケースがありますね。) [追記] 開平演算(√)命令も命令実行に時間が掛かる命令ですね。

    以下、ハードウェアマニュアルの画面コピーです。

    RX671グループ ユーザーズマニュアル ハードウェア編
    R01UH0899JJ0110 Rev.1.10 Pages 3084 2022.04.15
    www.renesas.com/jp/ja/document/mah/rx671-group-users-manual-hardware-rev100

     

  • こんにちは。NoMaYです。

    > なお、コンパイラには、命令実行に時間が掛かる命令(割り込みルーチンへ飛ぶのが遅れる命令)を使わないようにするコンパイルオプションもあります。

    具体的には、以下の画面コピーの、CC-RXの -nouse_div_inst というコンパイルオプションです。ちなみに、ICCRXにもGNURXにも類似のものは無いようでした。

    しかしながら、1つ前の投稿で命令実行時間を眺めていて気になったのですが、割り込み応答性を低下させる命令として他にも以下のものもありますね。後でコンパイラでの対応を調べてみようと思います。

    PUSHM命令(レジスタ数が多い場合(最大15レジスタ)) : 最大 15 クロック
    POPM命令(レジスタ数が多い場合(最大15レジスタ))  : 最大 15 or 15+1 クロック
    RTSD命令(レジスタ数が多い場合(最大15レジスタ))  : 最大 15+1 or 15+2 クロック

    DPUSHM命令(レジスタ数が多い場合(最大16レジスタ)) : 最大 16 クロック
    DPOPM命令(レジスタ数が多い場合(最大16レジスタ))  : 最大 16 or 16+1 クロック

    FSQRT命令 : 16 or 18 クロック

    DSQRT命令 : 33 or 33+1 クロック

     
    以下、CC-RXのヘルプの画面コピーです。



    [追記]

    RXv2までは、割り込み応答が最も低下するのは命令実行に 16 or 18 クロック掛かるFDIV命令やFSQRT命令の場合だったのだが、RXv3になって、命令実行に 33 or 33+1 クロック掛かるDDIV命令やDSQRT命令が追加されることになったので、その悪化分をレジスタ一括退避機能を搭載することで挽回出来るようにした、ということだったりするのだろうか、、、

    もしそうだったとしても、コンパイラは割り込み関数の先頭で必ずしも全てのレジスタと全てのアキュムレータを退避するようにしていたわけでは無いので、挽回するにはちょっと足りてないかな、というところだったりするのかも、、、

  • こんにちは。NoMaYです。

    > 割り込み応答性を低下させる命令として他にも以下のものもありますね。後でコンパイラでの対応を調べてみようと思います。

    考えてみれば、割り込み応答性を低下させてしまう開平演算(√)命令のFSQRT命令やDSQRT命令はC言語標準ライブラリのsqrt()族を使用しなければ良いだけで、案の定、CC-RXでも -nouse_div_inst といった系統のコンパイルオプションは存在しませんでした。(もちろん、ICCRXにもGNURXにも。) 他方、同じく割り込み応答性を低下させてしまう除算命令のFDIV命令やDDIV命令はC言語標準ライブラリの数学関数でのアルゴリズム実装において至る所で使用されていると思われますので、CC-RXの -nouse_div_inst コンパイルオプションで抑止しなければ手に負えないよね、とかも思いました。

    もちろん、C言語標準ライブラリのsqrt()族を使用しなければ良いだけ、といっても、当然ながら代替アルゴリズムを自前で用意する必要はありますけれども。(それは、自前でsqrt()を計算する関数を用意する、というやり方の他に、そもそも開平演算(√)を全く使用せずにプログラムとして所望の結果を導き出すことが出来る別の数学アルゴリズムに置き換える、というやり方もあり得ます。)

    他の割り込み応答性を低下させる命令に関しても、引き続きコンパイラでの対応を調べてみようと思います。

    [追記]

    ちなみに、FSQRT命令やDSQRT命令をダイレクトにコンパイラの生成コードで使用する場合には、C言語標準ライブラリの仕様で規定された errno 変数へのエラー番号の設定をどうするか、というトレードオフ問題が生じてしまうらしくて、その対応方法を選べるように、CC-RXもICCRXもGNURXも以下の画面コピーのコンパイルオプションを用意していました。(そして、それは何れのコンパイラでも、FDIV命令やDDIV命令を使うか使わないかを選ぶ、というのでは無かったです。)

    [訂正] すみません、GNURXは違ったようです。以下の -mrxv2-fsqrt オプションは文字通りにFSQRT命令に関するもので、DSQRT命令には関知していませんでした。そして、-mrxv2-fsqrt オプションを指定しない場合はFSQRT命令が使われなくなります。他方、-mrxv3-dsqrt オプションは存在しませんけれどもDSQRT命令は使われていました。標準ライブラリ内ではFSQRT命令もDSQRT命令も使われていなかったです。これは、どうも、FSQRT命令とDSQRT命令とでバランスがとても悪いことになっているようです。(歴史的経緯と互換性維持の兼ね合いによる落としどころなのだと思いますけれども。)

    以下、ヘルプの画面コピーです。

    CC-RX


    ICCRX


    GNURX