RXv3コアのレジスタ一括退避機能を使ってマルチスーパーループ実行ライブラリ(MultiSuperLoopExecLibrary)を作ってみるスレッド

こんにちは。NoMaYです。

今、以下のスレッドに投稿しているのですけれども、派生ネタが思い浮かびましたので、またひとつ立ててみました。

RXv3コアのレジスタ一括退避機能の使い方(Register Bank Save Function Usage)を調べてみるスレッド
community-ja.renesas.com/cafe_rene/forums-groups/mcu-mpu/rx/f/forum5/9572/rxv3-register-bank-save-function-usage

派生ネタ

・ スーパーループを複数同時実行する(複数のスーパーループを切り替えながら実行する)、という、ありがちなものです
・ RXv3コアのレジスタ一括退避機能の高速性を鑑みて10μsec程度で切り替えてみたいです
・ お遊びです

  • 思い浮かんだコードの断片のネタ(ネタの状態ですので動作は試していません)

    単に2つのスーパーループを切り替えるだけでもSAVE命令とRSTR命令にゴテゴテとコードが付加されて行きます、、、

    uint8_t SuperLoopCurrentContextId = 0;

    #if 0 /* Unfortunately CC-RX doesn't allow multiple #pragma for one function. */
    #pragma interrupt r_Config_CMT3_cmi3_interrupt(vect=VECT(PERIB,INTB129))
    #endif
    #pragma inline_asm r_Config_CMT3_cmi3_interrupt
    void r_Config_CMT3_cmi3_interrupt(void)
    {
        /* Re-enable interrupt. */
        setpsw i

        /* Save the current super loop context. Be aware that the USP is used from now. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        setpsw u
        sub #8, sp
        push.l r1
        mov.l #_SuperLoopCurrentContextId, r1
        mov.b [r1], r1
        save r1

        /* Move PSW, PC from the interrupt stack to the current super loop's user stack. */
        mvfc isp, r2
        mov.l 4[r2], 8[sp]
        mov.l 0[r2], 4[sp]
        add #8, r2
        mvtc r2, isp

        /* Select the next super loop. */
        add #1, r1
        and #1, r1
        mov.l #_SuperLoopCurrentContextId, r2
        mov.b r1, [r2]

        /* Restore the next super loop context. Be aware that the USP is used here. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        rstr r1
        pop r1
        rte
    }

     

  • 思い浮かんだコードの断片のネタ(ネタの状態ですので動作は試していません)

    CC-RXでWarning Levelを上げるとinline_asm関数の引数で出る未使用引数のInformation Messageを抑止出来た、、、

    /* Unfortunately CC-RX complains about unused parameters though inline_asm function. */
    /* Using intermediate function is a workaround for such CC-RX's information message. */
    #pragma inline_asm _Initialize_RegisterSaveBank
    static void _Initialize_RegisterSaveBank(void)
    {
        /* bank: r1 */
        /* pc:   r2 */
        /* usp:  r3 */

        /* Save PSW, USP to scratch registers and disable interrupt.  */
        mvfc psw, r4
        clrpsw i
        mvfc usp, r5

        /* Initialize the specified register save bank. */
        sub #12, r3     /* Reserve the space for PSW, PC and R1. */
        mvtc r3, usp    /* usp */
        mov.l r4, 8[r3] /* psw */
        mov.l r2, 4[r3] /* pc */
        mov.l r1, 0[r3] /* r1 but the value isn't important.*/
        save r1         /* Only the value of USP and FPSW are important. */

        /* Restore PSW, USP from scratch registers. */
        mvtc r5, usp
        mvtc r4, psw
    }

    /* Unfortunately CC-RX complains about unused parameters though inline_asm function. */
    /* Using intermediate function is a workaround for such CC-RX's information message. */
    #pragma noinline Initialize_RegisterSaveBank
    void Initialize_RegisterSaveBank(uint8_t bank, uint32_t pc, uint32_t usp)
    {
        (void) bank; /* r1 */
        (void) pc;   /* r2 */
        (void) usp;  /* r3 */
        _Initialize_RegisterSaveBank();
    }

     

  • RXマイコンには昔から高速割り込みという機能がありますが、以下のハードウェア編の画面コピーの通り、割り込みの受け付け時に2クロック、割り込みからのリターン時に3クロック、それぞれ実行クロックが通常の割り込みより少なくなります。ものは試しとして、この機能を利用するコードの断片を考えてみました。残念ながら、高速割り込み機能で使用されるレジスタはレジスタ一括退避機能の対象に含まれておらず、結局のところは、メモリ(スタック)への退避とメモリ(スタック)からの復帰が必要になってしまい、落としどころとしては、今ひとつなコードになってしまいました。

    思い浮かんだコードの断片のネタ(ネタの状態ですので動作は試していません)

    以下の緑文字部分が高速割り込みを使う場合の落としどころな気がします、、、

    #if 0 /* Unfortunately CC-RX doesn't allow multiple #pragma for one function. */
    #pragma interrupt r_Config_CMT3_cmi3_interrupt(vect=VECT(PERIB,INTB129),fint)
    #endif
    #pragma inline_asm r_Config_CMT3_cmi3_interrupt
    void r_Config_CMT3_cmi3_interrupt(void)
    {
        /* Re-enable interrupt. */
        setpsw i

        /* Save the current super loop context. Be aware that the USP is used from now. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        setpsw u
        sub #8, sp
        push.l r1
        mov.l #_SuperLoopCurrentContextId, r1
        mov.b [r1], r1
        save r1

        /* Copy PSW, PC from BPSW, BPC registers to the current super loop's user stack. */
        mvfc bpsw, r2
        mov.l r2, 8[sp]
        mvfc bpc, r3
        mov.l r3, 4[sp]

        /* Select the next super loop. */
        add #1, r1
        and #1, r1
        mov.l #_SuperLoopCurrentContextId, r2
        mov.b r1, [r2]

        /* Restore the next super loop context. Be aware that the USP is used here. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        rstr r1
        pop r1
        rte ← rtfiでは無くてrteを使います
    }

     
    先日の高速割り込みを使わない場合は以下の通りです。

    #if 0 /* Unfortunately CC-RX doesn't allow multiple #pragma for one function. */
    #pragma interrupt r_Config_CMT3_cmi3_interrupt(vect=VECT(PERIB,INTB129))
    #endif
    #pragma inline_asm r_Config_CMT3_cmi3_interrupt
    void r_Config_CMT3_cmi3_interrupt(void)
    {
        /* Re-enable interrupt. */
        setpsw i

        /* Save the current super loop context. Be aware that the USP is used from now. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        setpsw u
        sub #8, sp
        push.l r1
        mov.l #_SuperLoopCurrentContextId, r1
        mov.b [r1], r1
        save r1

        /* Move PSW, PC from the interrupt stack to the current super loop's user stack. */
        mvfc isp, r2
        mov.l 4[r2], 8[sp]
        mov.l 0[r2], 4[sp]
        add #8, r2
        mvtc r2, isp

        /* Select the next super loop. */
        add #1, r1
        and #1, r1
        mov.l #_SuperLoopCurrentContextId, r2
        mov.b r1, [r2]

        /* Restore the next super loop context. Be aware that the USP is used here. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        rstr r1
        pop r1
        rte
    }

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

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



     

  • なんというか、RTOSドメインとスーパーループドメインの2つがあって、10μsec程度で切り替わりながらプログラムが実行されて行く、みたいな実行モデルが実現出来ると、面白いのかなぁ、、、(それとも、それと同じことはRTOSの範疇内で出来てしまうかなぁ、、、) RTOSって、難しいですよね?でも、クラウド接続では無理矢理に使わされる、、、

    発想の発端:

    FreeRTOSのconfigTICK_RATE_HZに1001以上を設定した場合の、USB Host Mass Storage Class(r_usb_hmsc)の動作について
    community-ja.renesas.com/cafe_rene/forums-groups/mcu-mpu/rx/f/forum5/9740/freertos-configtick_rate_hz-1001-usb-host-mass-storage-class-r_usb_hmsc/47370#47370
     
    [追記] 2022/11/19

    > それとも、それと同じことはRTOSの範疇内で出来てしまうかなぁ、、、

    やりたいこと

    ・ スーパーループ処理で実行すべき事案がある時はスーパーループ処理を実行
    ・ スーパーループ処理で実行すべき事案が無い時はRTOSタスクを実行

    補足

    ・ スーパーループ処理で実行すべき事案が何も無くなった後では何かしらの然るべき割り込みの発生に伴ってスーパーループ処理で実行すべき事案が発生する
    ・ 例えばスーパーループ処理にて入力ポートをループ毎に監視するような事案は無く、例えば100μs毎とか1ms毎とか10ms毎とかのタイマ割り込みの発生に伴ってスーパーループ処理で事案が処理される



    ・ スーパーループ処理を最高優先度のタスクに割り当てる
    ・ スーパーループ処理で実行すべき事案が何も無くなった時にはタスク通知待ちに入る
    ・ スーパーループ処理を再開させる必要がある割り込みではスーパーループタスクにタスク通知を送ってタスク通知待ちを解除させる

    [追記] 2022/11/22

    > それとも、それと同じことはRTOSの範疇内で出来てしまうかなぁ、、、

    やりたいことのもうひとつの別方針

    ・ 実行すべきRTOSタスクが無い時はスーパーループ処理を実行
    ・ 実行すべきRTOSタスクがある時はRTOSタスクを実行



    ・ スーパーループ処理をタスク優先度1のスーパーループタスクに割り当てる
    ・ RTOSタスクはタスク優先度2以上に割り当てる
    ・ スーパーループ処理は今までと変わらない(FreeRTOS APIを呼び出さない)
    ・ スーパーループ処理向け割り込み処理は今までと変わらない(FreeRTOS APIを呼び出さない)

    補足

    ・ タスク優先度0のIdleタスクは実行されることがない(タスク優先度1のスーパーループタスクが実行され続けるから)
    ・ スーパーループ処理の中からRTOSタスクよりタスク優先度を高くしたい処理を切り出したくなったらFreeRTOS APIを触り始める(クラウド接続のRTOSタスクはレディメイドのブラックボックスとして扱う)

  • 先に挙げたものとは、構成が違いますが、μITRONドメインとAmazon FreeRTOSドメインを共存させる先例はあります。

    発想の先例:

    iSotEE: A Hypervisor Middleware for IoT-enabled Resource-constrained Reliable Systems
    github.com/iSotEE/isotee
    ieeexplore.ieee.org/document/9684412

    [関連リンク]

    Google検索: iSotEE TOPPERS
    www.google.co.jp/search?q=iSotEE+TOPPERS

    TOPPERS/HRP3
    www.toppers.jp/hrp3-kernel.html
    github.com/iSotEE/hrp3-rx65n-rsk
     

  • なんというか、RTOSドメインとスーパーループドメインの2つを用意するにあたって、一般的?とは逆向きみたいにRTOSドメインをMPU(メモリプロテクションユニット)で隔離する小細工って出来るだろうかなぁ、、、

  • FreeRTOSに、taskYIELD()という同一優先度で実行可能状態にある次のタスクへ行く、というAPIがあるのですけれども、それの真似事をするコードが思い浮かびました。

    思い浮かんだコードの断片のネタ(ネタの状態ですので動作は試していません)

    #if 0 /* Unfortunately CC-RX doesn't allow multiple #pragma for one function. */
    #pragma interrupt r_Config_CMT3_cmi3_interrupt(vect=VECT(PERIB,INTB129))
    #endif
    #pragma inline_asm r_Config_CMT3_cmi3_interrupt
    void r_Config_CMT3_cmi3_interrupt(void)
    {
    。。。先日のコード。。。
    }

    void SuperLoopYIELD(void)
    {
        int_exception(VECT(PERIB,INTB129));
    }

     
    [関連リンク]

    FreeRTOSのconfigTICK_RATE_HZに1001以上を設定した場合の、USB Host Mass Storage Class(r_usb_hmsc)の動作について
    community-ja.renesas.com/cafe_rene/forums-groups/mcu-mpu/rx/f/forum5/9740/freertos-configtick_rate_hz-1001-usb-host-mass-storage-class-r_usb_hmsc/47370#47370
     

  • すみません、前の投稿のSuperLoopYIELD()でIPLを操作するのを忘れていますね、、、

  • 派生元のスレッドの小細工マクロを使ってRXスマートコンフィグレータのCGコンポーネントのユーザ記述部にコードを押し込む案が思い浮かびました。(レジスタ一括退避バンクを1つとクロックを1クロックを無駄に使いますけれども。)

    ソース:

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

    #include "r_rx_nested_interrupt/r_rx_nested_interrupt.h"

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

     

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

    uint8_t SuperLoopCurrentContextId = 0;

    #pragma inline_asm MultiSuperLoop_Dispatch
    static void MultiSuperLoop_Dispatch(void)
    {
        /* Re-enable interrupt. */
        setpsw i

        /* Save the current super loop context. Be aware that the USP is used from now. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        setpsw u
        sub #8, sp
        push.l r1
        mov.l #_SuperLoopCurrentContextId, r1
        mov.b [r1], r1
        save r1

        /* Move PSW, PC from the interrupt stack to the current super loop's user stack. */
        mvfc isp, r2
        mov.l 4[r2], 8[sp]
        mov.l 0[r2], 4[sp]
        add #8, r2
        mvtc r2, isp

        /* Select the next super loop. */
        add #1, r1
        and #1, r1
        mov.l #_SuperLoopCurrentContextId, r2
        mov.b r1, [r2]

        /* Restore the next super loop context. Be aware that the USP is used here. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        rstr r1
        pop r1
        rte
    }

    #define r_Config_CMT3_cmi3_interrupt(...) R_CG_ATTRIB_INTERRUPT_BANK(r_Config_CMT3_cmi3_interrupt, MY_BSP_CFG_REG_BANK_SCRATCH, __VA_ARGS__)

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

     

    #if FAST_INTERRUPT_VECTOR == VECT_PERIB_INTB129
    #pragma interrupt r_Config_CMT3_cmi3_interrupt(vect=VECT(PERIB,INTB129),fint)
    #else
    #pragma interrupt r_Config_CMT3_cmi3_interrupt(vect=VECT(PERIB,INTB129))
    #endif
    static void r_Config_CMT3_cmi3_interrupt(void)
    {
        /* Start user code for r_Config_CMT3_cmi3_interrupt. Do not edit comment generated here */

        MultiSuperLoop_Dispatch();

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

     
    リスト:

    00000001                         __$r_Config_CMT3_cmi3_interrupt:
                                            .STACK  __$r_Config_CMT3_cmi3_interrupt=8
                                            .RVECTOR    129,__$r_Config_CMT3_cmi3_interrupt
    00000001 FD76E00F                       SAVE #0FH ← ここは無駄ですけれども
                                            ._LINE_TOP  inline_asm
    00000005 7FA8                        setpsw i
    00000007 7FA9                        setpsw u
    00000009 6080                        sub #8, sp
    0000000B 7EA1                        push.l r1
    0000000D FB12rrrrrrrr                mov.l #_SuperLoopCurrentContextId, r1
    00000013 CC11                        mov.b [r1], r1
    00000015 FD76C100                    save r1
    00000019 FD6AA2                      mvfc isp, r2
    0000001C E5200102                    mov.l 4[r2], 8[sp]
    00000020 E5200001                    mov.l 0[r2], 4[sp]
    00000024 6282                        add #8, r2
    00000026 FD682A                      mvtc r2, isp
    00000029 6211                        add #1, r1
    0000002B 6411                        and #1, r1
    0000002D FB22rrrrrrrr                mov.l #_SuperLoopCurrentContextId, r2
    00000033 C321                        mov.b r1, [r2]
    00000035 FD76D100                    rstr r1
    00000039 7EB1                        pop r1
    0000003B 7F95                        rte
                                            ._LINE_END  inline_asm
    0000003D FD76F00F                       RSTR #0FH ← ここは実行されません
    00000041 7F95                           RTE ← ここは実行されません

     

  • こんにちは。NoMaYです。

    2つのループを交互に切り替えるものをCC-RX/GNURX/ICCRXで作ってみました。一応ルネサスRXシミュレータで試してみていますけれども、まだ実機では試していません。プロジェクトのファイル一式を以下のzipファイルに固めました。

    issue_RXv3_MultiSuperLoop_20230121.zip

    以下、今時点での主要部分のソース(main.c×1+Config_CMT3_user.c×3)です。

    RXv3_MultiSuperLoop_{CCRX, GCC, IAR}/src/main.c

    main.c.20230121.txt
    #include "r_smc_entry.h"
    #include "MultiSuperLoop.h"
    
    void main(void);
    void main2(void);
    
    uint32_t ustack2[256 / sizeof(uint32_t)]; /* The stack should be 4 bytes alignment. */
    
    volatile int32_t debug;  /* The `volatile` keyword is for debug purpose. */
    volatile int32_t debug2; /* The `volatile` keyword is for debug purpose. */
    
    void main(void)
    {
        MultiSuperLoop_Add_Loop1( main2, (uint8_t *)ustack2 + sizeof(ustack2) );
    
        volatile int32_t autovar_debug;  /* The `volatile` keyword is for debug purpose. */
    
        autovar_debug = 1;
        for (;;)
        {
            debug = autovar_debug++;
            if (2000000000 <= autovar_debug)
            {
                autovar_debug = 1;
            }
            //MultiSuperLoop_Yield();
            if (0 >= autovar_debug || 2000000000 <= autovar_debug)
            {
                for (;;) { nop(); }
            }
        }
    }
    
    void main2(void)
    {
        volatile int32_t autovar_debug2; /* The `volatile` keyword is for debug purpose. */
    
        autovar_debug2 = -1;
        for (;;)
        {
            debug2 = autovar_debug2--;
            if (-2000000000 >= autovar_debug2)
            {
                autovar_debug2 = -1;
            }
            //MultiSuperLoop_Yield();
            if (0 <= autovar_debug2 || -2000000000 >= autovar_debug2)
            {
                for (;;) { nop(); }
            }
        }
    }
    

     
    RXv3_MultiSuperLoop_CCRX/src/smc_gen/Config_CMT3/Config_CMT3_user.c
    Config_CMT3_user.c.CCRX.20230121.txt
    /***********************************************************************************************************************
    * DISCLAIMER
    * This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products.
    * No other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all
    * applicable laws, including copyright laws. 
    * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING THIS SOFTWARE, WHETHER EXPRESS, IMPLIED
    * OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    * NON-INFRINGEMENT.  ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY
    * LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE FOR ANY DIRECT,
    * INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR
    * ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
    * Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability 
    * of this software. By using this software, you agree to the additional terms and conditions found by accessing the 
    * following link:
    * http://www.renesas.com/disclaimer
    *
    * Copyright (C) 2022 Renesas Electronics Corporation. All rights reserved.
    ***********************************************************************************************************************/
    
    /***********************************************************************************************************************
    * File Name        : Config_CMT3_user.c
    * Component Version: 2.3.0
    * Device(s)        : R5F566NNHxFP
    * Description      : This file implements device driver for Config_CMT3.
    ***********************************************************************************************************************/
    
    /***********************************************************************************************************************
    Pragma directive
    ***********************************************************************************************************************/
    /* Start user code for pragma. Do not edit comment generated here */
    /* End user code. Do not edit comment generated here */
    
    /***********************************************************************************************************************
    Includes
    ***********************************************************************************************************************/
    #include "r_cg_macrodriver.h"
    #include "Config_CMT3.h"
    /* Start user code for include. Do not edit comment generated here */
    
    #include "MultiSuperLoop.h"
    #include "r_rx_nested_interrupt/r_rx_nested_interrupt.h"
    
    /* End user code. Do not edit comment generated here */
    #include "r_cg_userdefine.h"
    
    /***********************************************************************************************************************
    Global variables and functions
    ***********************************************************************************************************************/
    /* Start user code for global. Do not edit comment generated here */
    
    R_BSP_PRAGMA_STATIC_INLINE_ASM(MultiSuperLoop_Dispatch)
    void MultiSuperLoop_Dispatch(void)
    {
    R_BSP_ASM_BEGIN
    
        /* Re-enable interrupt. */
        R_BSP_ASM( setpsw i                                         )
    
        /* Save the current super loop context. Be aware that the USP is used from now. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        R_BSP_ASM( setpsw u                                         )
        R_BSP_ASM( sub U_BSP_ASM_IMM(8), r0                         )
        R_BSP_ASM( push.l r1                                        )
        R_BSP_ASM( mov.l U_BSP_ASM_IMM(_SuperLoopContextTable), r1  )
        R_BSP_ASM( mov.b 16[r1], r1                                 )
        R_BSP_ASM( save r1                                          )
    
        /* Move PSW, PC from the interrupt stack to the current super loop's user stack. */
        R_BSP_ASM( mvfc isp, r2                                     )
        R_BSP_ASM( mov.l 4[r2], 8[r0]                               )
        R_BSP_ASM( mov.l 0[r2], 4[r0]                               )
        R_BSP_ASM( add U_BSP_ASM_IMM(8), r2                         )
        R_BSP_ASM( mvtc r2, isp                                     )
    
        /* Select the next super loop. */
        R_BSP_ASM( mov.l U_BSP_ASM_IMM(_SuperLoopContextTable), r2  )
        R_BSP_ASM( add r2, r1                                       )
        R_BSP_ASM( mov.b [r1], r1                                   )
        R_BSP_ASM( mov.b r1, 16[r2]                                 )
    
        /* Restore the next super loop context. Be aware that the USP is used here. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        R_BSP_ASM( rstr r1                                          )
        R_BSP_ASM( pop r1                                           )
        R_BSP_ASM( rte                                              )
    
    R_BSP_ASM_END
    }
    
    #define r_Config_CMT3_cmi3_interrupt(...) R_CG_ATTRIB_INTERRUPT_BANK(r_Config_CMT3_cmi3_interrupt, MY_BSP_CFG_REG_BANK_SCRATCH, __VA_ARGS__)
    
    /* End user code. Do not edit comment generated here */
    
    /***********************************************************************************************************************
    * Function Name: R_Config_CMT3_Create_UserInit
    * Description  : This function adds user code after initializing the CMT3 channel
    * Arguments    : None
    * Return Value : None
    ***********************************************************************************************************************/
    
    void R_Config_CMT3_Create_UserInit(void)
    {
        /* Start user code for user init. Do not edit comment generated here */
        /* End user code. Do not edit comment generated here */
    }
    
    /***********************************************************************************************************************
    * Function Name: r_Config_CMT3_cmi3_interrupt
    * Description  : This function is CMI3 interrupt service routine
    * Arguments    : None
    * Return Value : None
    ***********************************************************************************************************************/
    
    #if FAST_INTERRUPT_VECTOR == VECT_PERIB_INTB129
    #pragma interrupt r_Config_CMT3_cmi3_interrupt(vect=VECT(PERIB,INTB129),fint)
    #else
    #pragma interrupt r_Config_CMT3_cmi3_interrupt(vect=VECT(PERIB,INTB129))
    #endif
    static void r_Config_CMT3_cmi3_interrupt(void)
    {
        /* Start user code for r_Config_CMT3_cmi3_interrupt. Do not edit comment generated here */
    
        MultiSuperLoop_Dispatch();
    
        /* End user code. Do not edit comment generated here */
    }
    
    /* Start user code for adding. Do not edit comment generated here */
    
    /* Unfortunately CC-RX complains about unused parameters though inline_asm function. */
    /* Using intermediate function is a workaround for such CC-RX's information message. */
    R_BSP_PRAGMA_STATIC_INLINE_ASM(_Initialize_RegisterSaveBank)
    void _Initialize_RegisterSaveBank(void)
    {
        R_BSP_ASM_INTERNAL_USED(pc)   /* r1 */
        R_BSP_ASM_INTERNAL_USED(usp)  /* r2 */
        R_BSP_ASM_INTERNAL_USED(bank) /* r3 */
    
    R_BSP_ASM_BEGIN
    
        /* Save PSW, USP to scratch registers and disable interrupt.  */
        R_BSP_ASM( mvfc psw, r4                     )
        R_BSP_ASM( clrpsw i                         )
        R_BSP_ASM( mvfc usp, r5                     )
    
        /* Initialize the specified register save bank. */
        R_BSP_ASM( sub U_BSP_ASM_IMM(12), r2        ) /* Reserve the space for PSW, PC and R1. */
        R_BSP_ASM( mvtc r2, usp                     ) /* usp */
        R_BSP_ASM( mov.l r4, 8[r2]                  ) /* psw */
        R_BSP_ASM( mov.l r1, 4[r2]                  ) /* pc */
        R_BSP_ASM( mov.l U_BSP_ASM_IMM(0), 0[r2]    ) /* r1 but the value isn't important. */
        R_BSP_ASM( save r3                          ) /* Only the value of USP and FPSW are important. */
    
        /* Restore PSW, USP from scratch registers. */
        R_BSP_ASM( mvtc r5, usp                     )
        R_BSP_ASM( mvtc r4, psw                     )
    
    R_BSP_ASM_END
    }
    
    /* Unfortunately CC-RX complains about unused parameters though inline_asm function. */
    /* Using intermediate function is a workaround for such CC-RX's information message. */
    R_BSP_PRAGMA(noinline Initialize_RegisterSaveBank)
    static void Initialize_RegisterSaveBank(uint32_t pc, uint32_t usp, uint32_t bank)
    {
        (void) pc;   /* r1 */
        (void) usp;  /* r2 */
        (void) bank; /* r3 */
        _Initialize_RegisterSaveBank();
    }
    
    void MultiSuperLoop_Add_Loop1(void (*pc)(void), uint8_t *usp)
    {
        /* Prevent the debugger from messing up unwinding of the stack. */
        usp = (uint8_t *)usp - sizeof(uint32_t);
        *(uint32_t *)usp = 0;
    
        Initialize_RegisterSaveBank((uint32_t)pc, (uint32_t)usp, 1);
    
        SuperLoopContextTable[16] = 0;
    
        SuperLoopContextTable[ 0] = 1;
        SuperLoopContextTable[ 1] = 0;
        SuperLoopContextTable[ 2] = 255;
        SuperLoopContextTable[ 3] = 255;
        SuperLoopContextTable[ 4] = 255;
        SuperLoopContextTable[ 5] = 255;
        SuperLoopContextTable[ 6] = 255;
        SuperLoopContextTable[ 7] = 255;
        SuperLoopContextTable[ 8] = 255;
        SuperLoopContextTable[ 9] = 255;
        SuperLoopContextTable[10] = 255;
        SuperLoopContextTable[11] = 255;
        SuperLoopContextTable[12] = 255;
        SuperLoopContextTable[13] = 255;
        SuperLoopContextTable[14] = 255;
        SuperLoopContextTable[15] = 255;
    
        R_Config_CMT3_Start();
    }
    
    void MultiSuperLoop_Yield(void)
    {
        uint8_t ipl = get_ipl();
    
        if (ipl == 0)
        {
            set_ipl(1);
        }
    
        /* Switch to the next super loop. Be aware that the value of IPL is */
        /* also switched to the value which is used in the next super loop. */
        int_exception(VECT(PERIB,INTB129));
    
        if (ipl == 0)
        {
            set_ipl(0);
        }
    }
    
    /* End user code. Do not edit comment generated here */
    

     
    RXv3_MultiSuperLoop_GCC/src/smc_gen/Config_CMT3/Config_CMT3_user.c
    Config_CMT3_user.c.GNURX.20230121.txt
    /***********************************************************************************************************************
    * DISCLAIMER
    * This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products.
    * No other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all
    * applicable laws, including copyright laws. 
    * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING THIS SOFTWARE, WHETHER EXPRESS, IMPLIED
    * OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    * NON-INFRINGEMENT.  ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY
    * LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE FOR ANY DIRECT,
    * INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR
    * ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
    * Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability 
    * of this software. By using this software, you agree to the additional terms and conditions found by accessing the 
    * following link:
    * http://www.renesas.com/disclaimer
    *
    * Copyright (C) 2022 Renesas Electronics Corporation. All rights reserved.
    ***********************************************************************************************************************/
    
    /***********************************************************************************************************************
    * File Name        : Config_CMT3_user.c
    * Component Version: 2.3.0
    * Device(s)        : R5F566NNHxFP
    * Description      : This file implements device driver for Config_CMT3.
    ***********************************************************************************************************************/
    
    /***********************************************************************************************************************
    Pragma directive
    ***********************************************************************************************************************/
    /* Start user code for pragma. Do not edit comment generated here */
    /* End user code. Do not edit comment generated here */
    
    /***********************************************************************************************************************
    Includes
    ***********************************************************************************************************************/
    #include "r_cg_macrodriver.h"
    #include "Config_CMT3.h"
    /* Start user code for include. Do not edit comment generated here */
    
    #include "MultiSuperLoop.h"
    
    /* End user code. Do not edit comment generated here */
    #include "r_cg_userdefine.h"
    
    /***********************************************************************************************************************
    Global variables and functions
    ***********************************************************************************************************************/
    /* Start user code for global. Do not edit comment generated here */
    
    R_BSP_PRAGMA_STATIC_INLINE(MultiSuperLoop_Dispatch)
    void MultiSuperLoop_Dispatch(void)
    {
    R_BSP_ASM_BEGIN
    
        /* Re-enable interrupt. */
        R_BSP_ASM( setpsw i                                         )
    
        /* Save the current super loop context. Be aware that the USP is used from now. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        R_BSP_ASM( setpsw u                                         )
        R_BSP_ASM( sub U_BSP_ASM_IMM(8), r0                         )
        R_BSP_ASM( push.l r1                                        )
        R_BSP_ASM( mov.l U_BSP_ASM_IMM(_SuperLoopContextTable), r1  )
        R_BSP_ASM( mov.b 16[r1], r1                                 )
        R_BSP_ASM( save r1                                          )
    
        /* Move PSW, PC from the interrupt stack to the current super loop's user stack. */
        R_BSP_ASM( mvfc isp, r2                                     )
        R_BSP_ASM( mov.l 4[r2], 8[r0]                               )
        R_BSP_ASM( mov.l 0[r2], 4[r0]                               )
        R_BSP_ASM( add U_BSP_ASM_IMM(8), r2                         )
        R_BSP_ASM( mvtc r2, isp                                     )
    
        /* Select the next super loop. */
        R_BSP_ASM( mov.l U_BSP_ASM_IMM(_SuperLoopContextTable), r2  )
        R_BSP_ASM( add r2, r1                                       )
        R_BSP_ASM( mov.b [r1], r1                                   )
        R_BSP_ASM( mov.b r1, 16[r2]                                 )
    
        /* Restore the next super loop context. Be aware that the USP is used here. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        R_BSP_ASM( rstr r1                                          )
        R_BSP_ASM( pop r1                                           )
        R_BSP_ASM( rte                                              )
    
    R_BSP_ASM_END
    }
    
    void r_Config_CMT3_cmi3_interrupt(void) __attribute__((naked));
    
    /* End user code. Do not edit comment generated here */
    
    /***********************************************************************************************************************
    * Function Name: R_Config_CMT3_Create_UserInit
    * Description  : This function adds user code after initializing the CMT3 channel
    * Arguments    : None
    * Return Value : None
    ***********************************************************************************************************************/
    
    void R_Config_CMT3_Create_UserInit(void)
    {
        /* Start user code for user init. Do not edit comment generated here */
        /* End user code. Do not edit comment generated here */
    }
    
    /***********************************************************************************************************************
    * Function Name: r_Config_CMT3_cmi3_interrupt
    * Description  : This function is CMI3 interrupt service routine
    * Arguments    : None
    * Return Value : None
    ***********************************************************************************************************************/
    
    void r_Config_CMT3_cmi3_interrupt(void)
    {
        /* Start user code for r_Config_CMT3_cmi3_interrupt. Do not edit comment generated here */
    
        MultiSuperLoop_Dispatch();
    
        /* End user code. Do not edit comment generated here */
    }
    
    /* Start user code for adding. Do not edit comment generated here */
    
    R_BSP_PRAGMA_STATIC_INLINE_ASM(_Initialize_RegisterSaveBank)
    void _Initialize_RegisterSaveBank(uint32_t pc, uint32_t usp, uint32_t bank)
    {
        R_BSP_ASM_INTERNAL_USED(pc)   /* r1 */
        R_BSP_ASM_INTERNAL_USED(usp)  /* r2 */
        R_BSP_ASM_INTERNAL_USED(bank) /* r3 */
    
    R_BSP_ASM_BEGIN
    
        /* Save PSW, USP to scratch registers and disable interrupt.  */
        R_BSP_ASM( mvfc psw, r4                     )
        R_BSP_ASM( clrpsw i                         )
        R_BSP_ASM( mvfc usp, r5                     )
    
        /* Initialize the specified register save bank. */
        R_BSP_ASM( sub U_BSP_ASM_IMM(12), r2        ) /* Reserve the space for PSW, PC and R1. */
        R_BSP_ASM( mvtc r2, usp                     ) /* usp */
        R_BSP_ASM( mov.l r4, 8[r2]                  ) /* psw */
        R_BSP_ASM( mov.l r1, 4[r2]                  ) /* pc */
        R_BSP_ASM( mov.l U_BSP_ASM_IMM(0), 0[r2]    ) /* r1 but the value isn't important. */
        R_BSP_ASM( save r3                          ) /* Only the value of USP and FPSW are important. */
    
        /* Restore PSW, USP from scratch registers. */
        R_BSP_ASM( mvtc r5, usp                     )
        R_BSP_ASM( mvtc r4, psw                     )
    
    R_BSP_ASM_END
    }
    
    static void Initialize_RegisterSaveBank(uint32_t pc, uint32_t usp, uint32_t bank)
    {
        (void) pc;   /* r1 */
        (void) usp;  /* r2 */
        (void) bank; /* r3 */
        _Initialize_RegisterSaveBank(pc, usp, bank);
    }
    
    void MultiSuperLoop_Add_Loop1(void (*pc)(void), uint8_t *usp)
    {
        /* Prevent the debugger from messing up unwinding of the stack. */
        usp = (uint8_t *)usp - sizeof(uint32_t);
        *(uint32_t *)usp = 0;
    
        Initialize_RegisterSaveBank((uint32_t)pc, (uint32_t)usp, 1);
    
        SuperLoopContextTable[16] = 0;
    
        SuperLoopContextTable[ 0] = 1;
        SuperLoopContextTable[ 1] = 0;
        SuperLoopContextTable[ 2] = 255;
        SuperLoopContextTable[ 3] = 255;
        SuperLoopContextTable[ 4] = 255;
        SuperLoopContextTable[ 5] = 255;
        SuperLoopContextTable[ 6] = 255;
        SuperLoopContextTable[ 7] = 255;
        SuperLoopContextTable[ 8] = 255;
        SuperLoopContextTable[ 9] = 255;
        SuperLoopContextTable[10] = 255;
        SuperLoopContextTable[11] = 255;
        SuperLoopContextTable[12] = 255;
        SuperLoopContextTable[13] = 255;
        SuperLoopContextTable[14] = 255;
        SuperLoopContextTable[15] = 255;
    
        R_Config_CMT3_Start();
    }
    
    void MultiSuperLoop_Yield(void)
    {
        uint8_t ipl = get_ipl();
    
        if (ipl == 0)
        {
            set_ipl(1);
        }
    
        /* Switch to the next super loop. Be aware that the value of IPL is */
        /* also switched to the value which is used in the next super loop. */
        int_exception(VECT(PERIB,INTB129));
    
        if (ipl == 0)
        {
            set_ipl(0);
        }
    }
    
    /* End user code. Do not edit comment generated here */
    

     
    RXv3_MultiSuperLoop_IAR/src/smc_gen/Config_CMT3/Config_CMT3_user.c
    Config_CMT3_user.c.ICCRX.20230121.txt
    /***********************************************************************************************************************
    * DISCLAIMER
    * This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products.
    * No other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all
    * applicable laws, including copyright laws. 
    * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING THIS SOFTWARE, WHETHER EXPRESS, IMPLIED
    * OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    * NON-INFRINGEMENT.  ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY
    * LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE FOR ANY DIRECT,
    * INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR
    * ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
    * Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability 
    * of this software. By using this software, you agree to the additional terms and conditions found by accessing the 
    * following link:
    * http://www.renesas.com/disclaimer
    *
    * Copyright (C) 2022 Renesas Electronics Corporation. All rights reserved.
    ***********************************************************************************************************************/
    
    /***********************************************************************************************************************
    * File Name        : Config_CMT3_user.c
    * Component Version: 2.3.0
    * Device(s)        : R5F566NNHxFP
    * Description      : This file implements device driver for Config_CMT3.
    ***********************************************************************************************************************/
    
    /***********************************************************************************************************************
    Pragma directive
    ***********************************************************************************************************************/
    /* Start user code for pragma. Do not edit comment generated here */
    /* End user code. Do not edit comment generated here */
    
    /***********************************************************************************************************************
    Includes
    ***********************************************************************************************************************/
    #include "r_cg_macrodriver.h"
    #include "Config_CMT3.h"
    /* Start user code for include. Do not edit comment generated here */
    
    #include "MultiSuperLoop.h"
    
    /* End user code. Do not edit comment generated here */
    #include "r_cg_userdefine.h"
    
    /***********************************************************************************************************************
    Global variables and functions
    ***********************************************************************************************************************/
    /* Start user code for global. Do not edit comment generated here */
    
    R_BSP_PRAGMA_STATIC_INLINE(MultiSuperLoop_Dispatch)
    void MultiSuperLoop_Dispatch(void)
    {
    R_BSP_ASM_BEGIN
    
        /* Re-enable interrupt. */
        R_BSP_ASM( setpsw i                                         )
    
        /* Save the current super loop context. Be aware that the USP is used from now. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        R_BSP_ASM( setpsw u                                         )
        R_BSP_ASM( sub U_BSP_ASM_IMM(8), r0                         )
        R_BSP_ASM( push.l r1                                        )
        R_BSP_ASM( mov.l U_BSP_ASM_IMM(_SuperLoopContextTable), r1  )
        R_BSP_ASM( mov.b 16[r1], r1                                 )
        R_BSP_ASM( save r1                                          )
    
        /* Move PSW, PC from the interrupt stack to the current super loop's user stack. */
        R_BSP_ASM( mvfc isp, r2                                     )
        R_BSP_ASM( mov.l 4[r2], 8[r0]                               )
        R_BSP_ASM( mov.l 0[r2], 4[r0]                               )
        R_BSP_ASM( add U_BSP_ASM_IMM(8), r2                         )
        R_BSP_ASM( mvtc r2, isp                                     )
    
        /* Select the next super loop. */
        R_BSP_ASM( mov.l U_BSP_ASM_IMM(_SuperLoopContextTable), r2  )
        R_BSP_ASM( add r2, r1                                       )
        R_BSP_ASM( mov.b [r1], r1                                   )
        R_BSP_ASM( mov.b r1, 16[r2]                                 )
    
        /* Restore the next super loop context. Be aware that the USP is used here. */
        /* (As of today, the DPFPU registers are neither saved nor restored.) */
        R_BSP_ASM( rstr r1                                          )
        R_BSP_ASM( pop r1                                           )
        R_BSP_ASM( rte                                              )
    
    R_BSP_ASM_END
    }
    
    /* End user code. Do not edit comment generated here */
    
    /***********************************************************************************************************************
    * Function Name: R_Config_CMT3_Create_UserInit
    * Description  : This function adds user code after initializing the CMT3 channel
    * Arguments    : None
    * Return Value : None
    ***********************************************************************************************************************/
    
    void R_Config_CMT3_Create_UserInit(void)
    {
        /* Start user code for user init. Do not edit comment generated here */
        /* End user code. Do not edit comment generated here */
    }
    
    /***********************************************************************************************************************
    * Function Name: r_Config_CMT3_cmi3_interrupt
    * Description  : This function is CMI3 interrupt service routine
    * Arguments    : None
    * Return Value : None
    ***********************************************************************************************************************/
    
    #pragma vector = VECT_PERIB_INTB129
    #if FAST_INTERRUPT_VECTOR == VECT_PERIB_INTB129
    __fast_interrupt static void r_Config_CMT3_cmi3_interrupt(void)
    #else
    __interrupt static void r_Config_CMT3_cmi3_interrupt(void)
    #endif
    {
        /* Start user code for r_Config_CMT3_cmi3_interrupt. Do not edit comment generated here */
    
        MultiSuperLoop_Dispatch();
    
        /* End user code. Do not edit comment generated here */
    }
    
    /* Start user code for adding. Do not edit comment generated here */
    
    R_BSP_PRAGMA_STATIC_INLINE_ASM(_Initialize_RegisterSaveBank)
    void _Initialize_RegisterSaveBank(uint32_t pc, uint32_t usp, uint32_t bank)
    {
        R_BSP_ASM_INTERNAL_USED(pc)   /* r1 */
        R_BSP_ASM_INTERNAL_USED(usp)  /* r2 */
        R_BSP_ASM_INTERNAL_USED(bank) /* r3 */
    
    R_BSP_ASM_BEGIN
    
        /* Save PSW, USP to scratch registers and disable interrupt.  */
        R_BSP_ASM( mvfc psw, r4                     )
        R_BSP_ASM( clrpsw i                         )
        R_BSP_ASM( mvfc usp, r5                     )
    
        /* Initialize the specified register save bank. */
        R_BSP_ASM( sub U_BSP_ASM_IMM(12), r2        ) /* Reserve the space for PSW, PC and R1. */
        R_BSP_ASM( mvtc r2, usp                     ) /* usp */
        R_BSP_ASM( mov.l r4, 8[r2]                  ) /* psw */
        R_BSP_ASM( mov.l r1, 4[r2]                  ) /* pc */
        R_BSP_ASM( mov.l U_BSP_ASM_IMM(0), 0[r2]    ) /* r1 but the value isn't important. */
        R_BSP_ASM( save r3                          ) /* Only the value of USP and FPSW are important. */
    
        /* Restore PSW, USP from scratch registers. */
        R_BSP_ASM( mvtc r5, usp                     )
        R_BSP_ASM( mvtc r4, psw                     )
    
    R_BSP_ASM_END
    }
    
    static void Initialize_RegisterSaveBank(uint32_t pc, uint32_t usp, uint32_t bank)
    {
        (void) pc;   /* r1 */
        (void) usp;  /* r2 */
        (void) bank; /* r3 */
        _Initialize_RegisterSaveBank(pc, usp, bank);
    }
    
    void MultiSuperLoop_Add_Loop1(void (*pc)(void), uint8_t *usp)
    {
        /* Prevent the debugger from messing up unwinding of the stack. */
        usp = (uint8_t *)usp - sizeof(uint32_t);
        *(uint32_t *)usp = 0;
    
        Initialize_RegisterSaveBank((uint32_t)pc, (uint32_t)usp, 1);
    
        SuperLoopContextTable[16] = 0;
    
        SuperLoopContextTable[ 0] = 1;
        SuperLoopContextTable[ 1] = 0;
        SuperLoopContextTable[ 2] = 255;
        SuperLoopContextTable[ 3] = 255;
        SuperLoopContextTable[ 4] = 255;
        SuperLoopContextTable[ 5] = 255;
        SuperLoopContextTable[ 6] = 255;
        SuperLoopContextTable[ 7] = 255;
        SuperLoopContextTable[ 8] = 255;
        SuperLoopContextTable[ 9] = 255;
        SuperLoopContextTable[10] = 255;
        SuperLoopContextTable[11] = 255;
        SuperLoopContextTable[12] = 255;
        SuperLoopContextTable[13] = 255;
        SuperLoopContextTable[14] = 255;
        SuperLoopContextTable[15] = 255;
    
        R_Config_CMT3_Start();
    }
    
    void MultiSuperLoop_Yield(void)
    {
        uint8_t ipl = get_ipl();
    
        if (ipl == 0)
        {
            set_ipl(1);
        }
    
        /* Switch to the next super loop. Be aware that the value of IPL is */
        /* also switched to the value which is used in the next super loop. */
        int_exception(VECT(PERIB,INTB129));
    
        if (ipl == 0)
        {
            set_ipl(0);
        }
    }
    
    /* End user code. Do not edit comment generated here */