FreeRTOS kernelのRXv3-DPFPU port layerの作り方を考えてみようと思います

こんにちは。NoMaYです。

まだQiitaに掲題の投稿は見当たらなかったので考えてみようと思いました。RXv3コア搭載の品種の中でも、RX72M, RX72N, RX66Nには倍精度浮動小数点演算命令がありますが、命令の操作対象となるレジスタは、通常の汎用レジスタが使用される単精度浮動小数点演算の場合とは異なり、倍精度浮動小数点演算専用のレジスタが用意されています。また、命令の演算結果のフラグなどが格納されるレジスタも専用のものが用意されていますし、例外の発生制御を行ったり発生状況が格納されたりするレジスタにも専用のものが用意されています。ですが、既存のRXv2コア向けのFreeRTOSポートレイヤは、当然ながら、これらの倍精度浮動小数点演算専用のレジスタのことは考慮されておらず、タスク切り替え時にこれらのレジスタの内容の退避/復帰を行っていない為、タスク間で倍精度浮動小数点レジスタの値がぐちゃぐちゃに入り乱れることになってしまうので、倍精度浮動小数点演算命令の使用を諦めざるを得ないことになります。

これに対処する箇所は以下の4箇所(赤字箇所)かと思います。(まだ今は概念コードのレベルですが。)

port.c

#pragma inline_asm prvYieldHandler
static void prvYieldHandler( void )
{
    /* Re-enable interrupts. */
    SETPSW  I

    /* Move the data that was automatically pushed onto the interrupt stack when
    the interrupt occurred from the interrupt stack to the user stack.

    R15 is saved before it is clobbered. */
    PUSH.L  R15

    /* Read the user stack pointer. */
    MVFC    USP, R15

    /* Move the address down to the data being moved. */
    SUB     #12, R15
    MVTC    R15, USP

    /* Copy the data across. */
    MOV.L   [ R0 ], [ R15 ] ; R15
    MOV.L   4[ R0 ], 4[ R15 ]  ; PC
    MOV.L   8[ R0 ], 8[ R15 ]  ; PSW

    /* Move the interrupt stack pointer to its new correct position. */
    ADD #12, R0

    /* All the rest of the registers are saved directly to the user stack. */
    SETPSW  U

    /* Save the rest of the general registers (R15 has been saved already). */
    PUSHM   R1-R14
    /* Save the FPSW and accumulators. */
    MVFC    FPSW, R15
    PUSH.L  R15
    MVFACGU #0, A1, R15
    PUSH.L  R15
    MVFACHI #0, A1, R15
    PUSH.L  R15
    MVFACLO #0, A1, R15 ; Low order word.
    PUSH.L  R15
    MVFACGU #0, A0, R15
    PUSH.L  R15
    MVFACHI #0, A0, R15
    PUSH.L  R15
    MVFACLO #0, A0, R15 ; Low order word.
    PUSH.L  R15
    ここでタスク切り替え前の倍精度浮動小数点演算専用レジスタの値をスタックへ退避する
    /* Save the stack pointer to the TCB. */
    MOV.L   #_pxCurrentTCB, R15
    MOV.L   [ R15 ], R15
    MOV.L   R0, [ R15 ]

    /* Ensure the interrupt mask is set to the syscall priority while the kernel
    structures are being accessed. */
    MVTIPL  #configMAX_SYSCALL_INTERRUPT_PRIORITY

    /* Select the next task to run. */
    BSR.A   _vTaskSwitchContext

    /* Reset the interrupt mask as no more data structure access is required. */
    MVTIPL  #configKERNEL_INTERRUPT_PRIORITY

    /* Load the stack pointer of the task that is now selected as the Running
    state task from its TCB. */
    MOV.L   #_pxCurrentTCB,R15
    MOV.L   [ R15 ], R15
    MOV.L   [ R15 ], R0
    ここでタスク切り替え後の倍精度浮動小数点演算専用レジスタの値をスタックから復帰する
    /* Restore the context of the new task.  The PSW (Program Status Word) and
    PC will be popped by the RTE instruction. */
    POP     R15
    MVTACLO R15, A0     /* Accumulator low 32 bits. */
    POP     R15
    MVTACHI R15, A0     /* Accumulator high 32 bits. */
    POP     R15
    MVTACGU R15, A0     /* Accumulator guard. */
    POP     R15
    MVTACLO R15, A1     /* Accumulator low 32 bits. */
    POP     R15
    MVTACHI R15, A1     /* Accumulator high 32 bits. */
    POP     R15
    MVTACGU R15, A1     /* Accumulator guard. */
    POP     R15
    MVTC    R15,FPSW
    POPM    R1-R15
    RTE
    NOP
    NOP
}
#pragma inline_asm prvStartFirstTask
static void prvStartFirstTask( void )
{
    /* When starting the scheduler there is nothing that needs moving to the
    interrupt stack because the function is not called from an interrupt.
    Just ensure the current stack is the user stack. */
    SETPSW  U

    /* Obtain the location of the stack associated with which ever task
    pxCurrentTCB is currently pointing to. */
    MOV.L   #_pxCurrentTCB, R15
    MOV.L   [R15], R15
    MOV.L   [R15], R0
    ここでタスクのスタート時の倍精度浮動小数点演算専用レジスタの値をスタックから復帰する
    /* Restore the registers from the stack of the task pointed to by
    pxCurrentTCB. */
    POP     R15
    MVTACLO R15, A0     /* Accumulator low 32 bits. */
    POP     R15
    MVTACHI R15, A0     /* Accumulator high 32 bits. */
    POP     R15
    MVTACGU R15, A0     /* Accumulator guard. */
    POP     R15
    MVTACLO R15, A1     /* Accumulator low 32 bits. */
    POP     R15
    MVTACHI R15, A1     /* Accumulator high 32 bits. */
    POP     R15
    MVTACGU R15, A1     /* Accumulator guard. */
    POP     R15
    MVTC    R15,FPSW    /* Floating point status word. */
    POPM    R1-R15      /* R1 to R15 - R0 is not included as it is the SP. */
    RTE                 /* This pops the remaining registers. */
    NOP
    NOP
}
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
    /* R0 is not included as it is the stack pointer. */

    *pxTopOfStack = 0x00;
    pxTopOfStack--;
    *pxTopOfStack = portINITIAL_PSW;
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) pxCode;
    /* When debugging it can be useful if every register is set to a known
    value.  Otherwise code space can be saved by just setting the registers
    that need to be set. */
    #ifdef USE_FULL_REGISTER_INITIALISATION
    {
        pxTopOfStack--;
        *pxTopOfStack = 0xffffffff; /* r15. */
        pxTopOfStack--;
        *pxTopOfStack = 0xeeeeeeee;
        pxTopOfStack--;
        *pxTopOfStack = 0xdddddddd;
        pxTopOfStack--;
        *pxTopOfStack = 0xcccccccc;
        pxTopOfStack--;
        *pxTopOfStack = 0xbbbbbbbb;
        pxTopOfStack--;
        *pxTopOfStack = 0xaaaaaaaa;
        pxTopOfStack--;
        *pxTopOfStack = 0x99999999;
        pxTopOfStack--;
        *pxTopOfStack = 0x88888888;
        pxTopOfStack--;
        *pxTopOfStack = 0x77777777;
        pxTopOfStack--;
        *pxTopOfStack = 0x66666666;
        pxTopOfStack--;
        *pxTopOfStack = 0x55555555;
        pxTopOfStack--;
        *pxTopOfStack = 0x44444444;
        pxTopOfStack--;
        *pxTopOfStack = 0x33333333;
        pxTopOfStack--;
        *pxTopOfStack = 0x22222222;
        pxTopOfStack--;
    }
    #else
    {
        pxTopOfStack -= 15;
    }
    #endif
    ここでタスクのスタート時の倍精度浮動小数点演算専用レジスタの値をスタックに書き込む
    *pxTopOfStack = ( StackType_t ) pvParameters; /* R1 */
    pxTopOfStack--;
    *pxTopOfStack = portINITIAL_FPSW;
    pxTopOfStack--;
    *pxTopOfStack = 0x11111111; /* Accumulator 0. */
    pxTopOfStack--;
    *pxTopOfStack = 0x22222222; /* Accumulator 0. */
    pxTopOfStack--;
    *pxTopOfStack = 0x33333333; /* Accumulator 0. */
    pxTopOfStack--;
    *pxTopOfStack = 0x44444444; /* Accumulator 1. */
    pxTopOfStack--;
    *pxTopOfStack = 0x55555555; /* Accumulator 1. */
    pxTopOfStack--;
    *pxTopOfStack = 0x66666666; /* Accumulator 1. */
    return pxTopOfStack;
}

続く

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

    RX72N搭載の三角関数演算器(RXv3アーキテクチャ構成要素では無いですけれども)ですが、レジスタの仕様が公開されておらず自分が最初から諦めていたので問題意識として脇へ追いやっていたのですが、CC-RXで組み込み関数から普通に使えますし、コンパイルオプションを指定すれば数学ライブラリ内で使われるようにもなりますので、タスク切り替え時に退避/復帰することが出来るようにする何らかの実装があった方が良いとは思っているのですが、仕様が公開されていないので何も出来ていないです。

    RX72Nグループ ユーザーズマニュアル ハードウェア編
    www.renesas.com/jp/ja/search/keyword-search.html#genre=document&q=r01uh0824
    r01uh0824jj0100-rx72n.pdf
    三角関数演算器についての記載はこれだけです、、、

     

  • NoMaYさん

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

    本件、とても気になります。
    hirakuni45さんもご自身のブログ記事でこの点言及されてました。

    FreeRTOSのタスク切り替え時にどう処理すべきかを軸に少し調査してみます。
    また何かわかりましたらこの場で相談させてください。

    以上です

Reply
  • NoMaYさん

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

    本件、とても気になります。
    hirakuni45さんもご自身のブログ記事でこの点言及されてました。

    FreeRTOSのタスク切り替え時にどう処理すべきかを軸に少し調査してみます。
    また何かわかりましたらこの場で相談させてください。

    以上です

Children
No Data