LoginSignup
14
14

More than 1 year has passed since last update.

RXマイコン用 Renesas GNU-RX gcc-8.3.0 の利用

Last updated at Posted at 2020-07-12

GNU Tools と言う WEB ページ

お恥ずかしながら、最近見つけたのですが、Open Source Tools for Renesas と言う WEB ページがある事に気がつきました。

以前、ルネサスは、KPIT と言う企業と提携しており、そこが GNU 関係の開発環境をサポートしていました。
それが、無くなり、しばらくは、gcc-4.8.3 ベースのコンパイラを保守していたのは知っていましたが、今更、そんな古い gcc を使う気にならず、スルーしていました。

正規の gcc を取得して、それを自分でビルドして、アプリケーションをコンパイルして、十分な性能が出ていたので、あまり追及していませんでした。

ところが、RX72N の登場で、状況が一変します。

  • RXv3 コアの採用
  • 倍精度浮動小数点演算命令
  • TFU(三角関数演算器)の搭載

これらの機能は、正規の gcc ツリーにある、RX マイコン用コードだけではサポートされていません。
※これは、ルネサス社が、gcc のソースツリーに機能改善したコードをマージしない事が原因なのですが、その真意は判りません。

そんな時、上記 WEB ページで「登録」すれば、gcc-8.3.0 ベースのツールチェインがダウンロード出来る事が判り、試してみました。
※gcc-8.3.0 は C++17 に対応しており、自分のフレームワークをコンパイル可能です。

このページは、「CyberTHOR Studios Limited」が保守、管理していて、ルネサス製マイコン用 GNU ツールチェインをサポートするのが目的のようです。

ツールのダウンロードとインストール

「登録」が面倒なものの、ツールをダウンロードしてインストール出来ました。

ツールチェインは、Windows(多分 MinGW 環境による)版と Linux 版があり、ソースコードもダウンロードできます。
OS-X 環境の場合、Linux 版がある事から、ビルド出来るものと思います。

インストールには、登録メールアドレスに起因した「アクティベーションコード」が必要で、登録の際、メールで送られます。
※「登録」にはある程度の個人情報の提出が必要で(これは KPIT の場合もそうだった)、それが何故必要なのか判りません。

自分の場合、MSYS2 環境の CUI 環境で動かす事が「マスト」なので、以下のように、「.bash_profile」にパスを追加しました。

# rx-elf path
# PATH=$PATH:/usr/local/rx-elf/bin
PATH=$PATH:/C/'Program Files (x86)'/'GCC for Renesas RX 8.3.0.202002-GNURX-ELF'/rx-elf/rx-elf/bin

これで、MSYS2 のコンソールからでも、このコンパイラを利用可能です。

このツールチェインは以下の GNU ツールをアーカイブした物です。

  • binutils_rx_2.24_2020q2
  • gcc_rx_8.3.0_2020q2
  • newlib_rx_3.1.0_2020q2
  • gdb_rx_7.8.2_2020q2

このツール群は、ルネサスの IDE 環境(e2studio)などで、エミュレータによりデバッグ環境が充実するものと思います。

rx-elf-gcc の --target-help を実行すると、以下の表示が出ます。

% rx-elf-gcc --target-help
The following options are target specific:
  -fpu                        Enable the use of RX FPU instructions.  This is
                              the default.
  -m32bit-doubles             Stores doubles in 32 bits.  This is the default.
  -m64bit-doubles             Store doubles in 64 bits.
  -mallow-string-insns        Enables or disables the use of the SMOVF, SMOVB,
                              SMOVU, SUNTIL, SWHILE and RMPA instructions.
                              Enabled by default.
  -mas100-syntax              Generate assembler output that is compatible with
                              the Renesas AS100 assembler.  This may restrict
                              some of the compiler's capabilities.  The default
                              is to generate GAS compatible syntax.
  -mbig-endian-data           Data is stored in big-endian format.
  -mcpu=                      Specify the target RX cpu type.
  -mdfpu                      Enable the use of RX DFPU instructions.
  -mgcc-abi                   Enable the use of the old, broken, ABI where all
                              stacked function arguments are aligned to 32-bits.
  -mint-register=             Specifies the number of registers to reserve for
                              interrupt handlers.
  -misa=                      Specify RX ISA version.
  -mjsr                       Always use JSR, never BSR, for calls.
  -mlarge-function-growth=    Permited value of the limit growth of large
                              function (in percent).
  -mlittle-endian-data        Data is stored in little-endian format.
                              (Default).
  -mlra                       Enable the use of the LRA register allocator.
  -mmax-constant-size=        Maximum size in bytes of constant values allowed
                              as operands.
  -mno-balign                 Do not use .balign
  -mpid                       Enables Position-Independent-Data (PID) mode.
  -mrelax                     Enable linker relaxation.
  -mrx-abi                    Enable the use the standard RX ABI where all
                              stacked function arguments are naturally aligned.
                              This is the default.
  -mrxpeephole                Coremark improvement.
  -mrxv2-fsqrt                Enable to use of FSQRT hardware instruction for
                              RXv2 instruction set
  -msave-acc-in-interrupts    Specifies whether interrupt functions should save
                              and restore the accumulator register.
  -msim                       Use the simulator runtime.
  -msmall-data-limit=         Maximum size of global and static variables which
                              can be placed into the small data area.
  -mtfu=                      Enable the use of RX TFU instructions.
  -mwarn-multiple-fast-interrupts Warn when multiple, different, fast interrupt
                              handlers are in the compilation unit.
  -nofpu                      Disable the use of RX FPU instructions.

Assembler options
=================

Use "-Wa,OPTION" to pass "OPTION" to the assembler.

 RX specific command line options:
  --mbig-endian-data
  --mlittle-endian-data [default]
  --m32bit-doubles [default]
  --m64bit-doubles
  --muse-conventional-section-names
  --muse-renesas-section-names [default]
  --msmall-data-limit
  --mrelax
  --mpid
  --mint-register=<value>
  --mcpu=<rx100|rx200|rx230|rx600|rx610|rx64m|rx66T|rx71m|rx72T>
  --misa=<v1|v2|v3>
  --mno-allow-string-insns  --mgcc-abi
  --mrx-abi [default]

Linker options
==============

Use "-Wl,OPTION" to pass "OPTION" to the linker.

elf32rx:
  --build-id[=STYLE]          Generate build ID note
  -z common-page-size=SIZE    Set common page size to SIZE
  -z defs                     Report unresolved symbols in object files.
  -z execstack                Mark executable as requiring executable stack
  -z max-page-size=SIZE       Set maximum page size to SIZE
  -z muldefs                  Allow multiple definitions
  -z noexecstack              Mark executable as not requiring executable stack
  --no-flag-mismatch-warnings Don't warn about objects with incompatible
                                endian or dsp settings
  --flag-mismatch-warnings    Warn about objects with incompatible
                                endian, dsp or ABI settings
  --ignore-lma                Ignore segment LMAs [default]
                                (for Renesas Tools compatibility)
  --no-ignore-lma             Don't ignore segment LMAs

ここで、「-mdfpu」、「-mtfu=」の RX72N にとって重要な二つのオプションがあります。

Renesas GNU-RX 8.3.0 のオプションの違い

Renesas 版を使う場合に、厄介なのは、正規ツリーの gcc とオプションが異なる点です。
※正規の gcc では、大雑把に言うと、RXv1 コアしかサポートされていないと言えますが、それでも、通常のアプリケーションでも、そんなに性能低下する事なく、アプリケーションを動かせます。
また、binutils は、最新版を使う事で、RXv3 の命令をアセンブル可能なので、C++/C ソースコードにアセンブラ命令を直で書く事が出来るので、FreeRTOS などでも何とかなっていました。

とりあえず、Makefile 中の、RX マイコンのオプションを修正して、 自分のプロジェクト全体を、リリースビルド、デバッグビルドでコンパイルしてみました。

-mcpu= オプションには、RX72N は無いのですが、以下のオプションで、実質、RX72N 用となります。

「-mcpu=<rx100|rx200|rx230|rx600|rx610|rx64m|rx66T|rx71m|rx72T>」

    -misa=v3

コンパイルは問題無く、全て通ったので、幾つかのアプリケーションを動かしてみました。

これも当然ながら、問題無く動作しました。

ここまで来ると、Renesas GNU-RX を使う事に何らハードルは無いものと思えます。

Makefile のオプションを GNU-RX 用に修正すると、正規の gcc の場合にコンパイルが出来ないので、Makefile の制御文を考えてみました。

# rx-elf-gcc compiler version check
TARGET_ISA_TEXT := $(shell rx-elf-gcc --target-help | grep ISA)

# AS_DEFS       =   --defsym NOT_USER=1
ifeq ($(TARGET_ISA_TEXT), )
# gcc-7.5.0 current gcc source build
CC_DEFS     =   -mcpu=rx600 -Wa,-mcpu=rxv2
CP_DEFS     =   -mcpu=rx600
else # Renesas GNU-RX gcc
CC_DEFS     =   -misa=v3
# CP_DEFS       =   -misa=v3 -mdfpu -mtfu=intrinsic,mathlib
CP_DEFS     =   -misa=v3 -mtfu=intrinsic,mathlib
# CP_DEFS       =   -misa=v3 -mdfpu
endif

これは、「--target-help」を実行して、その中に「ISA」の文字列があれば、Renesas 版と判断するものです。

Renesas GNU-RX 8.3.0 の最適化性能

いつもの RAYTRACE_sample を動かすと、少しだけ「速い」事に気がつきました。

※正規ツリーの gcc-7.5.0 では、「361ms」

そこで、簡単なプログラムをコンパイルして、アセンブルリストを見てみました。

以下は、LED 点滅のメインループです。

    typedef device::PORT<device::PORT0, device::bitpos::B1> LED;

    while(1) {
        utils::delay::milli_second(250);
        LED::P = 0;
        utils::delay::milli_second(250);
        LED::P = 1;
    }

ここで、LED のポートに、「1」、「0」を書く部分に注目しました。

gcc-7.5.0 の場合、以下のようなコードになります。

ffc0029c:       cc 3e                           mov.b   [r3], r14
ffc0029e:       75 42 fa                        mov.l   #250, r2
ffc002a1:       75 2e fe                        and     #-2, r14
ffc002a4:       c3 3e                           mov.b   r14, [r3]

ffc002bc:       cc 3e                           mov.b   [r3], r14
ffc002be:       65 1e                           or      #1, r14
ffc002c0:       c3 3e                           mov.b   r14, [r3]

論理演算が使用されていますが、割と普通です。

GNU-RX 8.3.0 では

ffc00278:       f0 38                           bclr    #0, [r3].b

ffc00294:       f0 30                           bset    #0, [r3].b

ビット操作命令になっています。
※これは、gcc-4.8.x のツールチェインで、既に実装済みでした。

多分、上記以外にも、コアの違いによる専用命令など、割と細かい部分で、最適化が行われて、「高速化」したものと思います。

倍精度浮動小数点命令

次に、「-mdfpu」を調べてみました。

    -misa=v3 -mdfpu

「-mdfpu」のオプションは、コアが RXv3 である必要があり、「-misa=v3」も必要です。

以下の簡単なプログラム

    double a = 0.0;
    while(1) {
        utils::delay::milli_second(250);
        LED::P = 0;
        utils::delay::milli_second(250);
        LED::P = 1;
        a += 0.1;
        utils::format("%5.4f\n") % static_cast<float>(a);
    }

で、アセンブラ命令を見てみると・・・

ffc003d2:       fc c9 08 12 10                  dmov.D 72[r0], dr1
ffc003d7:       f9 03 00 9a 99 99 99            dmov.L #0x9999999a, drl0
ffc003de:       f9 03 02 99 99 b9 3f            dmov.L #0x3fb99999, drh0
ffc003e5:       76 90 00 11                     dadd  dr1, dr0, dr1
ffc003e9:       fc 79 08 12 10                  dmov.D dr1, 72[r0]

上記のように、「倍精度浮動小数点命令」が使われています。
※ 64 ビットの IEEE-754 で定数 0.1 の表現は、0x3fb9'9999'9999'999a となります。
※ 64 ビットの定数をレジスターにロードするコストは大きいようです・・・

TFU(三角関数演算器)の利用

RX72N には、TFU(三角関数演算器)が内蔵されています。
ですが、仕様は公開されていません、コンパイラのサポートが必要です。

また、GNU-RX で TFU を有効にする場合の解説を見つけられなかったので、GNU-RX のソースコードを取得して、その部分を少し読んでみました。

gcc のソースコード「gcc/config/rx/rx.opt」を見ると・・・

EnumValue
Enum(rx_tfu_types) String(intrinsic) Value(RX_INTRINSIC)

EnumValue
Enum(rx_tfu_types) String(intrinsic,mathlib) Value(RX_MATHLIB)

とあり、「-mtfu=」の定数として、

    -mtfu=intrinsic

    -mtfu=intrinsic,mathlib

のどちらかを設定すれば良さそうだと判ります。

「gcc/config/rx/rx.c」で、

    if (TARGET_TFU)
    {
      ADD_RX_TFU_BUILTIN (INIT, "__init_tfu", void);
      ADD_RX_BUILTIN3 (SINCOSF, "sincosf", void, float, float_ptr, float_ptr);
      ADD_RX_BUILTIN4 (ATAN2HYPOTF, "atan2hypotf", void, float, float, float_ptr, float_ptr);
      if (rx_tfu_type == RX_MATHLIB)
      {
        ADD_RX_BUILTIN1 (SINF, "sinf", float, float);
        ADD_RX_BUILTIN1 (COSF, "cosf", float, float);
        ADD_RX_BUILTIN2 (ATAN2F, "atan2f", float, float, float);
        ADD_RX_BUILTIN2 (HYPOTF, "hypotf", float, float, float);
      }
    }

となっており、上記 API が使える事が判ります。

色々調べると、この API はビルトイン関数として登録されるようです。
関数のプロトタイプは、以下のようになっています。

    // -mtfu=intrinsic
    void __init_tfu(void);
    void __builtin_rx_sincosf(float, float*, float*);
    void __builtin_rx_atan2hypotf(float, float, float*, float*);
    // -mtfu=intrinsic,mathlib
    float __builtin_rx_sinf(float);
    float __builtin_rx_cosf(float);
    float __builtin_rx_atan2f(float, float);
    float __builtin_rx_hypotf(float, float);

これら API の仕様は、C の数学ライブラリに準拠するようです。
このプロトタイプ宣言は、「-mtfu=」を設定する事で内部的に「有効」になります。

これら、ビルトイン関数を利用する場合、多分、事前に初期化関数を呼んでおく必要があるようです。
※ビルトイン関数が有効になると、内蔵変数「__TFU」も有効になります。

#if definrd(__TFU)
    __init_tfu();
#endif

後は、普通に関数を呼べば良いものと思います。

    float a = vtx::get_pi<float>() * 0.25f;
    float si, co;
    __builtin_rx_sincosf(a, &si, &co);
    utils::format("%8.7f: %8.7f, %8.7f\n") % a % si % co;
    a = vtx::get_pi<float>() * 1.75f;
    si = __builtin_rx_sinf(a);
    co = __builtin_rx_cosf(a);
    utils::format("%8.7f: %8.7f, %8.7f\n") % a % si % co;
0.7853982: 0.7071068, 0.7071067
5.4977875: -0.7071068, 0.7071067

倍精度浮動小数点演算、TFU のパフォーマンス

ルネサスの HP に以下の資料を見つけました。

RXv3 CPU搭載RXファミリ 数値計算用ライブラリ関数ベンチマーク

むすび

これで、最新の RX72N を使い、GNU-RX gcc-8.3.0 で、十分な性能を出す土台が揃ったと言えます。

今後、他のオプションについても、色々研究していこうと思います。

それにしても、これら gcc への追加機能を、正規の gcc ソースツリーにマージしないのは何故なのか疑問は残ります・・

14
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14