こんにちは。NoMaYです。e2 studio v6.3.0がリリースされていたので、インストールして幾つかプロジェクトを作成して、いつものようにe2 studioのインストールフォルダを眺めていたら、CCRXmachine.hとCCRXmachine.cというファイルがあることに気付きました。中を見てみると、概ねファイル名から予想される通りのソースファイルでした。(今までのe2 studioのインストールフォルダを見直してみたところ、以前からあったことが分かりましたが、今まで気付きませんでした。) ただ、一部コメントアウトされているものがあったり、以前に別スレッド『GUNRX用プロジェクトのスマートコンフィグレータのBSPを見ていて気付いた変な移植コード』で話題にしたことと同じ元のコードの意図を理解していない書き換えがあったり、ちょっと惜しいような気もしました。e2 studioインストールフォルダ\internal\projectgen\rx\Generate\CCRXConversion\inc\CCRXmachine.he2 studioインストールフォルダ\internal\projectgen\rx\Generate\CCRXConversion\inc\CCRXmachine.c
こんにちは。NoMaYです。GNURX(というかGCC)のインラインアセンブラは難しいですね。以下のドキュメントを読みながら書いているのですが、(当たり前ですが)書き方を間違えると期待したコードが生成されませんね、、、(悲しいことに、まだ私は何が間違っていて何が正しい書き方なのかを理解出来るレベルに到達していない、、、)6.45.2 Extended Asm - Assembler Instructions with C Expression Operandsgcc.gnu.org/onlinedocs/gcc/Extended-Asm.html今までのコード ⇒ OK
static __inline__ void xchg(signed long *data1, signed long *data2) __attribute__((always_inline));static __inline__ void xchg(signed long *data1, signed long *data2){/* CC-RX V2.03 MOV.L [R1], R14 XCHG [R2].L, R14 MOV.L R14, [R1] RTS*/ signed long temp = *data1; __asm__ volatile ( /* AssemblerTemplate */ "XCHG [%[R2]].L, %[R14]" : /* OutputOperands */ [R14] "+r" (temp) : /* InputOperands */ [R2] "r" (data2) ); *data1 = temp; return;/* GNURX 2018q1 91 0010 EC 15 mov.L [r1], r5 95 0012 06 A0 10 25 XCHG [r2].L, r5 99 0016 E3 15 mov.L r5, [r1] 100 0018 02 rts*/}
試しに書き換えてみた ⇒ NG
static __inline__ void xchg(signed long *data1, signed long *data2) __attribute__((always_inline));static __inline__ void xchg(signed long *data1, signed long *data2){/* CC-RX V2.03 MOV.L [R1], R14 XCHG [R2].L, R14 MOV.L R14, [R1] RTS*/ signed long temp; /* = *data1; */ __asm__ volatile ( /* AssemblerTemplate */ "MOV.L [%[R1]], %[R14]\n\t" "XCHG [%[R2]].L, %[R14]\n\t" "MOV.L %[R14], [%[R1]]" : /* OutputOperands */ [R14] "=r" (temp) : /* InputOperands */ [R1] "r" (data1), [R2] "r" (data2) ); /* *data1 = temp; */ return;/* GNURX 2018q1 92 0010 EC 12 MOV.L [r1], r2 ← r2を壊してしまった 93 0012 06 A0 10 22 XCHG [r2].L, r2 94 0016 E3 12 MOV.L r2, [r1] 97 0018 02 rts*/}
更に書き換えてみた ⇒ OK
static __inline__ void xchg(signed long *data1, signed long *data2) __attribute__((always_inline));static __inline__ void xchg(signed long *data1, signed long *data2){/* CC-RX V2.03 MOV.L [R1], R14 XCHG [R2].L, R14 MOV.L R14, [R1] RTS*/ signed long temp; __asm__ volatile ( /* AssemblerTemplate */ "MOV.L %[mR1], %[R14]\n\t" "XCHG %[mR2].L, %[R14]\n\t" "MOV.L %[R14], %[mR1]" : /* OutputOperands */ [R14] "=r" (temp), [mR1] "+m" (*data1), [mR2] "+m" (*data2) ); return;/* GNURX 2018q1 92 0010 EC 15 MOV.L [r1], r5 93 0012 06 A0 10 25 XCHG [r2].L, r5 94 0016 E3 15 MOV.L r5, [r1] 97 0018 02 rts*/}
ちなみに、まだ試行錯誤中ですが、CC-RXで積和演算を行うrmpab()関数は積和演算命令のレジスタの使い方が特徴的だったせいで苦し紛れにGNURXで以下のように記述してみたのですが、コンパイラの最適化処理の足枷になってしまうのでしょうが、他の関数でも同様に変数に割り当てるレジスタを強制的に指定しておいてから他のコンパイラでインラインアセンブラを使う時と同様の感覚で記述する(たぶん記述出来るのではないかと思う)、というやり方にも心惹かれます。(でも、今回のCCRXmachine2.hではやらないつもりですが、、、)(補 GNURXで%r0のようなレジスタ表記も出来るのですね。GNURX Migration Guide : Inline_Assemblygcc-renesas.com/migration-guides/rx/index.html#Inline_Assembly以下のコードは以下のドキュメントを読みながら書いていました。6.45.5.2 Specifying Registers for Local Variablesgcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html)
static __inline__ long long rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2) __attribute__((always_inline));static __inline__ long long rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2){/* CC-RX V2.03 ARG init = R2:R1 ARG count = R3 ARG addr1 = R4 ARG addr2 = 04H[R0](08H[R0] after push R6) RET R2:R1 PUSH.L R6 MOV.L R1, R14 MOV.L R2, R5 MOV.L 08H[R0], R2 SHAR #1FH, R5, R6 MOV.L R4, R1 MOV.L R14, R4 RMPA.B MOV.L R5, R2 MOV.L R4, R1 RTSD #04H, R6-R6*/ register signed char *r1 __asm__("r1") = addr1; register signed char *r2 __asm__("r2") = addr2; register unsigned long r3 __asm__("r3") = count; register long long r5r4 __asm__("r4") = init; register signed long r6 __asm__("r6") = (signed long)(init >> 63); __asm__ volatile ( /* AssemblerTemplate */ "RMPA.B" : /* OutputOperands */ "+r" (r5r4), "+r" (r6) : /* InputOperands */ "X" (r1), "X" (r2), "X" (r3) ); return r5r4;/* GNURX 2018q1 111 0019 7E A6 push.l r6 113 001b 60 40 sub #4, r0 116 001d EF 25 mov.L r2, r5 117 001f EF 1E mov.L r1, r14 122 0021 EF 41 mov.L r4, r1 125 0023 A8 8A mov.L 12[r0], r2 128 0025 EF E4 mov.L r14, r4 131 0027 FD BF 56 shar #31, r5, r6 134 002a 7F 8C RMPA.B 139 002c EF 41 mov.L r4, r1 141 002e EF 52 mov.L r5, r2 142 0030 3F 66 02 rtsd #8, r6-r6*/}
積和演算命令のレジスタの使い方は以下のようにストリング操作命令同様(というかそれ以上)に特徴的ですね。RXファミリ ユーザーズマニュアル ソフトウェア編www.renesas.com/ja-jp/doc/products/mpumcu/doc/rx_family/r01us0032jj0120_rxsm.pdfなお、GNURX対応のCCRXmachin.cのrmpab()関数は以下のように積和演算命令は使わずに記述されていました。
long long rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2){ long long result = init; unsigned long index; for(index = 0; index < count; index++) { result += addr1[index] * addr2[index]; } return result;}