こんにちは。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対応のCCRXmachine.cを見ていて、以下のコードの末尾にCC-RXのスタートアップルーチンで見掛けたChange_PSW_PM_to_UserMode()関数の末尾にあるNOP命令が無いことに気付きました。(もっとも、随分以前からCC-RXではビルトイン関数のchg_pmusr()関数が使われるようになっていますので、今はCC-RXでChange_PSW_PM_to_UserMode()関数を見掛けることは余りありませんが。) そのせいで、以下のGNURX対応のCCRXmachine.cのchg_pmusr()関数は誤動作すると思われます。CCRXmachine.c
void chg_pmusr(void){ __asm("MVFC PSW,R1" : : :"r1"); __asm("OR #00100000h,R1" : : :"r1"); __asm("PUSH.L R1" : : :"r1"); __asm("MVFC PC,R1" : : :"r1"); __asm("ADD #10,R1" : : :"r1"); __asm("PUSH.L R1" : : :"r1"); __asm("RTE");}
CC-RXのスタートアップルーチンで見掛けたChange_PSW_PM_to_UserMode()関数は以下のコードです。このコードはもともとトリッキーなもので、MVFC PC,R1命令の先頭アドレスに10(0xA)を足したアドレスにRTEして分岐するようになっていますが、その分岐先アドレスは末尾の2つ目のNOP命令の先頭アドレスになります。generate\resetprg.c
#pragma inline_asm Change_PSW_PM_to_UserModestatic void Change_PSW_PM_to_UserMode(void);static void Change_PSW_PM_to_UserMode(void){ MVFC PSW,R1 OR #00100000h,R1 PUSH.L R1 MVFC PC,R1 ADD #10,R1 PUSH.L R1 RTE NOP NOP}
例えば、上のコードをCC-RX V2.03のresetprg.cに組み込んでコンパイルすると以下のようになります。generate\resetprg.lst
; 123 // _CALL_INIT(); // Remove the comment when you use global class object ; 124 ; 125 set_psw(PSW_init); // Set Ubit & Ibit for PSW00000031 FD68E0 MVTC R14, PSW ; 126 Change_PSW_PM_to_UserMode(); // Remove the comment when you need to change PSW PMbit (SuperVisor->User) ._LINE_TOP inline_asm00000034 FD6A01 MVFC PSW,R100000037 7731000010 OR #00100000h,R10000003C 7EA1 PUSH.L R10000003E FD6A11 MVFC PC,R1 メモ: 0x3E+0xA=0x4800000041 62A1 ADD #10,R100000043 7EA1 PUSH.L R100000045 7F95 RTE00000047 03 NOP00000048 03 NOP ._LINE_END inline_asm ; 127 ; 128 main();00000049 05rrrrrr A BSR _main
ところが、GNURX対応のCCRXmachine.cのchg_pmusr()関数ではNOP命令がありませんので、GNURXの2018q1でコンパイルしてみると以下のように、分岐先アドレスがchg_pmusr()関数の最後のRTS命令の次のアドレスになってしまいます、、、CCRXmachine.lst
242:../src/CCRXmachine.c **** void chg_pmusr(void) 243:../src/CCRXmachine.c **** { 244:../src/CCRXmachine.c **** __asm("MVFC PSW,R1" : : :"r1"); 307 00cf FD 6A 01 MVFC PSW,R1 245:../src/CCRXmachine.c **** __asm("OR #00100000h,R1" : : :"r1"); 311 00d2 77 31 00 00 10 OR #00100000h,R1 246:../src/CCRXmachine.c **** __asm("PUSH.L R1" : : :"r1"); 315 00d7 7E A1 PUSH.L R1 247:../src/CCRXmachine.c **** __asm("MVFC PC,R1" : : :"r1"); 319 00d9 FD 6A 11 MVFC PC,R1 メモ: 0xd9+0xa=0xe3 248:../src/CCRXmachine.c **** __asm("ADD #10,R1" : : :"r1"); 323 00dc 62 A1 ADD #10,R1 249:../src/CCRXmachine.c **** __asm("PUSH.L R1" : : :"r1"); 327 00de 7E A1 PUSH.L R1 250:../src/CCRXmachine.c **** __asm("RTE"); 331 00e0 7F 95 RTE 333 00e2 02 rts 253:../src/CCRXmachine.c **** void set_acc(signed long long data) 254:../src/CCRXmachine.c **** { 255:../src/CCRXmachine.c **** __builtin_rx_mvtachi(data >> 32); 343 00e3 FD 17 02 mvtachi r2 メモ: ここはもうchg_pmusr()関数の外部です 256:../src/CCRXmachine.c **** __builtin_rx_mvtaclo(data & 0xFFFFFFFF); 345 00e6 FD 17 11 mvtaclo r1
[追記]そういえば、以前に別スレッド『RX631のメモリプロテクションユニットの件』で経験しましたが、chg_pmusr()関数(というかChange_PSW_PM_to_UserMode()関数)はIスタックからUスタックへの切り替えが発生しますので、そもそも、インライン展開されない場合には使用方法が難しい関数でもあります。なお、CC-RXの場合ですが、これら2つの関数は実装が微妙に異なり、正直に言うと動作確認はしていないのですが、Change_PSW_PM_to_UserMode()関数(≒GNURX対応のCCRXmachine.cのchg_pmusr()関数)はユーザモード中に実行すると特権命令例外が発生すると思われるのに対し、もう一方のchg_pmusr()関数はユーザモード中に実行しても特権命令例外が発生しないと思われます。(理由は、chg_pmusr()関数の方はPSWを調べてユーザモード中だったら特権命令であるRTE命令を実行しないようになっていましたので、そのようになると考えています。)