こんにちは。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命令を実行しないようになっていましたので、そのようになると考えています。)
ほやです。自己亀レスで済みません。
> ただし-fltoを付けないと関数呼び出しになってしまうのは変わりません。 関数本体の宣言の前にalways_inline 付けても効きませんでした。これについて少し補足します。__attribute__((always_inline) の宣言は、これを宣言したソースの中に関数本体がある事を要求されます。現状のように xchg( )関数のプロトタイプをCCRXmachine.hに置き、本体をCCRXmachine.cに置いた状態ではヘッダ側にalways_inlineを付けて宣言できません。
> 「ヘッダファイルに~」とある通り、CCRXmachine.c ではなく CCRXmachine.h に記述する話をしています。xchg関数1つならそれもアリなのですが、他の組み込み関数までヘッダに記述するのはムリがあるかと。
だからと言ってCCRXmachine.cの中だけでalways_inlineを付けて宣言しても、別のソースからcallした場合はalways_inlineが見えていないので常にはinline展開されません。
「always_inline 付けても効きませんでした」はそういう意味でした。
xchg( )を関数の形でなくビルトイン関数を呼び出すマクロとして再定義した方が手間が減る気がします。CCRXmachine.hの中で、マクロに書き換えられるものをマクロに、関数でないと難しいものだけ関数で宣言してあれば良かったのではないかと思います。
以上独り言でした。
こんにちは。NoMaYです。別スレッド『Amazon FreeRTOSだそうです。ルネサスさんのRXは参加しないのかな?』でCC-RX用プロジェクトをGNURX用プロジェクトへ移植する際に作ろうと考えていたCCRXmachine2.hの作業を始めようとして気付きましたが、前の投稿のchg_pmusr()関数の他にCC-RXの特殊なビルトイン関数としてint_exception()関数がありました。このint_exception()関数はCC-RXで以下のような記述をするとエラーになります。
void my_int_exception(signed long num);void my_int_exception(signed long num){ int_exception(num);}
F0544802:The value of the parameter for the in-line function is outside the defined range.
これは、作ろうとしているCCRXmachine2.hでは、以下のようなマクロにするしかないかなと考えています。
#define int_exception( num ) _int_exception_cpp_step2( num )#define _int_exception_cpp_step2( num ) do{ __asm __volatile ("INT #" #num); } while(0)
理由は、以下の通り、INT命令のオペランドに割り込み番号をイミディエート値で指定する必要があるからです。
RXファミリ ユーザーズマニュアル ソフトウェア編www.renesas.com/ja-jp/doc/products/mpumcu/doc/rx_family/r01us0032jj0120_rxsm.pdfちなみに、コメントアウトされていますが、GNURX対応のCCRXmachine.cでも以下の記述が見られ、特殊である予感はしていました。
/*略#define INTN(N)\ case N:\ __builtin_rx_int(N);#define INTN5(N)\ INTN(N)\ INTN(N+1)\ INTN(N+2)\ INTN(N+3)\ INTN(N+4)\#define INTN10(N)\ INTN5(N)\ INTN5(N+5)\#define INTN50(N)\ INTN10(N)\ INTN10(N+10)\ INTN10(N+20)\ INTN10(N+30)\ INTN10(N+40)void int_exception(signed long num){ switch(num) { INTN50(0) INTN50(50) INTN50(100) INTN50(150) INTN50(200) INTN5(250) INTN(255) default: __builtin_rx_int(255); }}略*/
ところで、CCRXmachine2.hの作業の手始めとして、以下のCソースをCC-RX V2.03でコンパイルしてアセンブラソースを出力させてみました。CCRX_machine_h.c
#include <machine.h> /* * https://www.renesas.com/ja-jp/doc/products/tool/doc/011/r20ut3248jj0105-ccrx.pdf * 表4.26 (356頁 ~ 359頁 / 全970頁) */ void _dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_(void) { ; } signed long _max(signed long data1, signed long data2) { return _builtin_max(data1, data2); } signed long _min(signed long data1, signed long data2) { return _builtin_min(data1, data2); } unsigned long _revl(unsigned long data) { return _builtin_revl(data); } unsigned long _revw(unsigned long data) { return _builtin_revw(data); } void _xchg(signed long *data1, signed long *data2) { _builtin_xchg(data1, data2); } long long _rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2) { return _builtin_rmpab(init, count, addr1, addr2); } long long _rmpaw(long long init, unsigned long count, short *addr1, short *addr2) { return _builtin_rmpaw(init, count, addr1, addr2); } long long _rmpal(long long init, unsigned long count, long *addr1, long *addr2) { return _builtin_rmpal(init, count, addr1, addr2); } unsigned long _rolc(unsigned long data) { return _builtin_rolc(data); } unsigned long _rorc(unsigned long data) { return _builtin_rorc(data); } unsigned long _rotl(unsigned long data, unsigned long num) { return _builtin_rotl(data, num); } unsigned long _rotr(unsigned long data, unsigned long num) { return _builtin_rotr(data, num); } void _brk(void) { _builtin_brk(); } // void _int_exception(signed long num) { _builtin_int_exception(num); } // F0544802:The value of the parameter for the in-line function is outside the defined range. void _wait(void) { _builtin_wait(); } void _nop(void) { _builtin_nop(); } void _set_ipl(signed long level) { _builtin_set_ipl(level); } unsigned char _get_ipl(void) { return _builtin_get_ipl(); } void _set_psw(unsigned long data) { _builtin_set_psw(data); } unsigned long _get_psw(void) { return _builtin_get_psw(); } void _set_fpsw(unsigned long data) { _builtin_set_fpsw(data); } unsigned long _get_fpsw(void) { return _builtin_get_fpsw(); } void _set_usp(void *data) { _builtin_set_usp(data); } void * _get_usp(void) { return _builtin_get_usp(); } void _set_isp(void *data) { _builtin_set_isp(data); } void * _get_isp(void) { return _builtin_get_isp(); } void _set_intb(void *data) { _builtin_set_intb(data); } void * _get_intb(void) { return _builtin_get_intb(); } void _set_bpsw(unsigned long data) { _builtin_set_bpsw(data); } unsigned long _get_bpsw(void) { return _builtin_get_bpsw(); } void _set_bpc(void *data) { _builtin_set_bpc(data); } void * _get_bpc(void) { return _builtin_get_bpc(); } void _set_fintv(void *data) { _builtin_set_fintv(data); } void * _get_fintv(void) { return _builtin_get_fintv(); } signed long long _emul(signed long data1, signed long data2) { return _builtin_emul(data1, data2); } unsigned long long _emulu(unsigned long data1, unsigned long data2) { return _builtin_emulu(data1, data2); } short _macw1(short *data1, short *data2, unsigned long count) { return _builtin_macw1(data1, data2, count); } short _macw2(short *data1, short *data2, unsigned long count) { return _builtin_macw2(data1, data2, count); } long _macl(short *data1, short *data2, unsigned long count) { return _builtin_macl(data1, data2, count); } void _chg_pmusr(void) { _builtin_chg_pmusr(); } void _set_acc(signed long long data) { _builtin_set_acc(data); } signed long long _get_acc(void) { return _builtin_get_acc(); } void _setpsw_i(void) { _builtin_setpsw_i(); } void _clrpsw_i(void) { _builtin_clrpsw_i(); } void _set_extb(void *data) { _builtin_set_extb(data); } void * _get_extb(void) { return _builtin_get_extb(); } /* * 表4.26の最後の3項目 (CC-RX V2.05 or later) */ #if __RENESAS_VERSION__ >= 0x02050000 void _dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy2(void) { ; } void _bclr(unsigned char *data, unsigned long bit) { __bclr(data, bit); } void _bnot(unsigned char *data, unsigned long bit) { __bnot(data, bit); } void _bset(unsigned char *data, unsigned long bit) { __bset(data, bit); } #endif
;RX Family C/C++ Compiler (V2.03.00.03 [04 Dec 2014]) 08-Jun-2018 18:56:32 ;*** CPU TYPE *** ;-ISA=RXV2 ;*** COMMAND PARAMETER *** ;-output=src=CCRX_machine_h.src ;-isa=rxv2 ;-fpu ;-include=C:\Renesas\CS_~1\CC\CC-RX\V203~1.00\include,C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\generate ;-lang=c ;-nomessage ;-obj_path=src ;-debug ;-listfile=src/CCRX_machine_h.lst ;-show=source,conditionals,definitions,expansions ;-asm_path=src ;-nologo ;CCRX_machine_h.c .glb __dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_ .glb __max .glb __min .glb __revl .glb __revw .glb __xchg .glb __rmpab .glb __rmpaw .glb __rmpal .glb __rolc .glb __rorc .glb __rotl .glb __rotr .glb __brk .glb __wait .glb __nop .glb __set_ipl .glb __get_ipl .glb __set_psw .glb __get_psw .glb __set_fpsw .glb __get_fpsw .glb __set_usp .glb __get_usp .glb __set_isp .glb __get_isp .glb __set_intb .glb __get_intb .glb __set_bpsw .glb __get_bpsw .glb __set_bpc .glb __get_bpc .glb __set_fintv .glb __get_fintv .glb __emul .glb __emulu .glb __macw1 .glb __macw2 .glb __macl .glb __chg_pmusr .glb __set_acc .glb __get_acc .glb __setpsw_i .glb __clrpsw_i .glb __set_extb .glb __get_extb ;LineNo. C-SOURCE STATEMENT .SECTION P,CODE __dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_: .STACK __dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_=4 ; 1 #include <machine.h> ; 2 ; 3 /* ; 4 * https://www.renesas.com/ja-jp/doc/products/tool/doc/011/r20ut3248jj0105-ccrx.pdf ; 5 * 表4.26 (356頁 ~ 359頁 / 全970頁) ; 6 */ ; 7 void _dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_(void) { ; } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",7 RTS __max: .STACK __max=4 ; 8 signed long _max(signed long data1, signed long data2) { return _builtin_max(data1, data2); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",8 MAX R2, R1 RTS __min: .STACK __min=4 ; 9 signed long _min(signed long data1, signed long data2) { return _builtin_min(data1, data2); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",9 MIN R2, R1 RTS __revl: .STACK __revl=4 ; 10 unsigned long _revl(unsigned long data) { return _builtin_revl(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",10 REVL R1, R1 RTS __revw: .STACK __revw=4 ; 11 unsigned long _revw(unsigned long data) { return _builtin_revw(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",11 REVW R1, R1 RTS __xchg: .STACK __xchg=4 ; 12 void _xchg(signed long *data1, signed long *data2) { _builtin_xchg(data1, data2); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",12 MOV.L [R1], R14 XCHG [R2].L, R14 MOV.L R14, [R1] RTS __rmpab: .STACK __rmpab=8 ; 13 long long _rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2) { return _builtin_rmpab(init, count, addr1, addr2); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",13 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 __rmpaw: .STACK __rmpaw=8 ; 14 long long _rmpaw(long long init, unsigned long count, short *addr1, short *addr2) { return _builtin_rmpaw(init, count, addr1, addr2); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",14 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.W MOV.L R5, R2 MOV.L R4, R1 RTSD #04H, R6-R6 __rmpal: .STACK __rmpal=8 ; 15 long long _rmpal(long long init, unsigned long count, long *addr1, long *addr2) { return _builtin_rmpal(init, count, addr1, addr2); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",15 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.L MOV.L R5, R2 MOV.L R4, R1 RTSD #04H, R6-R6 __rolc: .STACK __rolc=4 ; 16 unsigned long _rolc(unsigned long data) { return _builtin_rolc(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",16 ROLC R1 RTS __rorc: .STACK __rorc=4 ; 17 unsigned long _rorc(unsigned long data) { return _builtin_rorc(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",17 RORC R1 RTS __rotl: .STACK __rotl=4 ; 18 unsigned long _rotl(unsigned long data, unsigned long num) { return _builtin_rotl(data, num); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",18 ROTL R2, R1 RTS __rotr: .STACK __rotr=4 ; 19 unsigned long _rotr(unsigned long data, unsigned long num) { return _builtin_rotr(data, num); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",19 ROTR R2, R1 RTS __brk: .STACK __brk=4 ; 20 void _brk(void) { _builtin_brk(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",20 BRK RTS __wait: .STACK __wait=4 ; 21 // void _int_exception(signed long num) { _builtin_int_exception(num); } ; 22 // F0544802:The value of the parameter for the in-line function is outside the defined range. ; 23 void _wait(void) { _builtin_wait(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",23 WAIT RTS __nop: .STACK __nop=4 ; 24 void _nop(void) { _builtin_nop(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",24 NOP RTS __set_ipl: .STACK __set_ipl=4 ; 25 void _set_ipl(signed long level) { _builtin_set_ipl(level); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",25 MVFC PSW, R14 SHLL #1CH, R1 SHLR #04H, R1 AND #0F0FFFFFFH, R14 OR R14, R1 MVTC R1, PSW RTS __get_ipl: .STACK __get_ipl=4 ; 26 unsigned char _get_ipl(void) { return _builtin_get_ipl(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",26 MVFC PSW, R14 REVL R14, R1 AND #0FH, R1 RTS __set_psw: .STACK __set_psw=4 ; 27 void _set_psw(unsigned long data) { _builtin_set_psw(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",27 MVTC R1, PSW RTS __get_psw: .STACK __get_psw=4 ; 28 unsigned long _get_psw(void) { return _builtin_get_psw(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",28 MVFC PSW, R1 RTS __set_fpsw: .STACK __set_fpsw=4 ; 29 void _set_fpsw(unsigned long data) { _builtin_set_fpsw(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",29 MVTC R1, FPSW RTS __get_fpsw: .STACK __get_fpsw=4 ; 30 unsigned long _get_fpsw(void) { return _builtin_get_fpsw(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",30 MVFC FPSW, R1 RTS __set_usp: .STACK __set_usp=4 ; 31 void _set_usp(void *data) { _builtin_set_usp(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",31 MVTC R1, USP RTS __get_usp: .STACK __get_usp=4 ; 32 void * _get_usp(void) { return _builtin_get_usp(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",32 MVFC USP, R1 RTS __set_isp: .STACK __set_isp=4 ; 33 void _set_isp(void *data) { _builtin_set_isp(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",33 MVTC R1, ISP RTS __get_isp: .STACK __get_isp=4 ; 34 void * _get_isp(void) { return _builtin_get_isp(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",34 MVFC ISP, R1 RTS __set_intb: .STACK __set_intb=4 ; 35 void _set_intb(void *data) { _builtin_set_intb(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",35 MVTC R1, INTB RTS __get_intb: .STACK __get_intb=4 ; 36 void * _get_intb(void) { return _builtin_get_intb(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",36 MVFC INTB, R1 RTS __set_bpsw: .STACK __set_bpsw=4 ; 37 void _set_bpsw(unsigned long data) { _builtin_set_bpsw(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",37 MVTC R1, BPSW RTS __get_bpsw: .STACK __get_bpsw=4 ; 38 unsigned long _get_bpsw(void) { return _builtin_get_bpsw(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",38 MVFC BPSW, R1 RTS __set_bpc: .STACK __set_bpc=4 ; 39 void _set_bpc(void *data) { _builtin_set_bpc(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",39 MVTC R1, BPC RTS __get_bpc: .STACK __get_bpc=4 ; 40 void * _get_bpc(void) { return _builtin_get_bpc(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",40 MVFC BPC, R1 RTS __set_fintv: .STACK __set_fintv=4 ; 41 void _set_fintv(void *data) { _builtin_set_fintv(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",41 MVTC R1, FINTV RTS __get_fintv: .STACK __get_fintv=4 ; 42 void * _get_fintv(void) { return _builtin_get_fintv(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",42 MVFC FINTV, R1 RTS __emul: .STACK __emul=4 ; 43 signed long long _emul(signed long data1, signed long data2) { return _builtin_emul(data1, data2); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",43 MOV.L R1, R4 EMUL R2, R4 MOV.L R5, R2 MOV.L R4, R1 RTS __emulu: .STACK __emulu=4 ; 44 unsigned long long _emulu(unsigned long data1, unsigned long data2) { return _builtin_emulu(data1, data2); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",44 MOV.L R1, R4 EMULU R2, R4 MOV.L R5, R2 MOV.L R4, R1 RTS __macw1: .STACK __macw1=4 ; 45 short _macw1(short *data1, short *data2, unsigned long count) { return _builtin_macw1(data1, data2, count); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",45 CMP #00H, R3 MOV.L #00000000H, R14 MULLO R14, R14 BEQ L52 L47: ; entry BTST #00H, R3 BGEU L49 L48: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L48 BRA L52 L49: ; entry SUB #01H, R3 BEQ L51 L50: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L50 L51: ; entry MOV.W [R1], R14 MOV.W [R2], R5 MACLO R14, R5 L52: ; entry RACW #01H MVFACHI R1 RTS __macw2: .STACK __macw2=4 ; 46 short _macw2(short *data1, short *data2, unsigned long count) { return _builtin_macw2(data1, data2, count); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",46 CMP #00H, R3 MOV.L #00000000H, R14 MULLO R14, R14 BEQ L59 L54: ; entry BTST #00H, R3 BGEU L56 L55: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L55 BRA L59 L56: ; entry SUB #01H, R3 BEQ L58 L57: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L57 L58: ; entry MOV.W [R1], R14 MOV.W [R2], R5 MACLO R14, R5 L59: ; entry RACW #02H MVFACHI R1 RTS __macl: .STACK __macl=4 ; 47 long _macl(short *data1, short *data2, unsigned long count) { return _builtin_macl(data1, data2, count); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",47 CMP #00H, R3 MOV.L #00000000H, R14 MULLO R14, R14 BEQ L66 L61: ; entry BTST #00H, R3 BGEU L63 L62: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L62 BRA L66 L63: ; entry SUB #01H, R3 BEQ L65 L64: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L64 L65: ; entry MOV.W [R1], R14 MOV.W [R2], R5 MACLO R14, R5 L66: ; entry MVFACMI R1 RTS __chg_pmusr: .STACK __chg_pmusr=12 ; 48 void _chg_pmusr(void) { _builtin_chg_pmusr(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",48 MVFC PSW, R14 BTST #14H, R14 BNE L69 L68: ; entry OR #00100000H, R14 PUSH.L R14 L70: MVFC PC, R14 ADD #L69-L70, R14 PUSH.L R14 RTE L69: ; entry RTS __set_acc: .STACK __set_acc=4 ; 49 void _set_acc(signed long long data) { _builtin_set_acc(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",49 MVTACLO R1 MVTACHI R2 RTS __get_acc: .STACK __get_acc=4 ; 50 signed long long _get_acc(void) { return _builtin_get_acc(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",50 MVFACMI R1 SHLL #10H, R1 MVFACHI R2 RTS __setpsw_i: .STACK __setpsw_i=4 ; 51 void _setpsw_i(void) { _builtin_setpsw_i(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",51 SETPSW I RTS __clrpsw_i: .STACK __clrpsw_i=4 ; 52 void _clrpsw_i(void) { _builtin_clrpsw_i(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",52 CLRPSW I RTS __set_extb: .STACK __set_extb=4 ; 53 void _set_extb(void *data) { _builtin_set_extb(data); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",53 MVTC R1, EXTB RTS __get_extb: .STACK __get_extb=4 ; 54 void * _get_extb(void) { return _builtin_get_extb(); } .LINE "C:\Renesas\e2_studio_63_rl78rxrza\workspace_e2_v630\TestCCRX_machine_h\src\CCRX_machine_h.c",54 MVFC EXTB, R1 RTS ; 55 ; 56 /* ; 57 * 表4.26の最後の3項目 (CC-RX V2.05 or later) ; 58 */ ; 59 #if __RENESAS_VERSION__ >= 0x02050000 ; 60 void _dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy_dummy2(void) { ; } ; 61 void _bclr(unsigned char *data, unsigned long bit) { __bclr(data, bit); } ; 62 void _bnot(unsigned char *data, unsigned long bit) { __bnot(data, bit); } ; 63 void _bset(unsigned char *data, unsigned long bit) { __bset(data, bit); } ; 64 #endif .END
以下のようなマクロにするしかないかなと考えています。 #define int_exception( num ) _int_exception_cpp_step2( num ) #define _int_exception_cpp_step2( num ) do{ __asm __volatile ("INT #" #num); } while(0)
#define int_exception( num ) _int_exception_cpp_step2( num ) #define _int_exception_cpp_step2( num ) do{ __asm __volatile ("INT #" #num); } while(0)
↑ だと、
$ cat -n intexception.c 1 #define int_exception( num ) _int_exception_cpp_step2( num ) 2 #define _int_exception_cpp_step2( num ) do{ __asm __volatile ("INT #" #num); } while(0) 3 4 void hoge(void) 5 { 6 int_exception(0); 7 int_exception(1); 8 int_exception(2); 9 int_exception(255); 10 int num = 123; 11 int_exception(num); 12 extern int ext; 13 int_exception(ext); 14 } $
↑のようなソースを書いた場合、
$ rx-elf-gcc -Wall -Wextra -O2 intexception.c -S -o - .file "intexception.c" intexception.c: In function 'hoge': intexception.c:12:16: warning: unused variable 'ext' [-Wunused-variable] extern int ext; ^ intexception.c:10:9: warning: unused variable 'num' [-Wunused-variable] int num = 123; ^ .section P,"ax" .global _hoge .type _hoge, @function _hoge: ; 6 "intexception.c" 1 INT #0 ; 0 "" 2 ; 7 "intexception.c" 1 INT #1 ; 0 "" 2 ; 8 "intexception.c" 1 INT #2 ; 0 "" 2 ; 9 "intexception.c" 1 INT #255 ; 0 "" 2 ; 11 "intexception.c" 1 INT #num ; 0 "" 2 ; 13 "intexception.c" 1 INT #ext ; 0 "" 2 rts .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $
引数に変数を使用した場合に期待した命令が出力されません。
マクロをちょっと書き換えて
$ cat -n intexception.c 1 #define int_exception( num ) _int_exception_cpp_step2( num ) 2 #define _int_exception_cpp_step2( num ) \ 3 do { \ 4 if (__builtin_constant_p(num)) { \ 5 __asm __volatile("INT %0 \n"::"i"(num)); \ 6 } else { \ 7 switch ((num) & 255) { \ 8 case 0: __asm __volatile("INT #0 \n"); break; \ 9 case 1: __asm __volatile("INT #1 \n"); break; \ 10 case 2: __asm __volatile("INT #2 \n"); break; \
~ 長いので略 ~
263 case 255: __asm __volatile("INT #255 \n"); break; \ 264 } \ 265 } \ 266 } while (0); 267 268 void hoge(void) 269 { 270 int_exception(0); 271 int_exception(1); 272 int_exception(2); 273 int_exception(255); 274 int num = 123; 275 int_exception(num); 276 extern int ext; 277 int_exception(ext); 278 }
等とすると、
$ rx-elf-gcc -Wall -Wextra -O2 intexception.c -S -o - .file "intexception.c" .section P,"ax" .global _hoge .type _hoge, @function _hoge: ; 270 "intexception.c" 1 INT #0 ; 0 "" 2 ; 271 "intexception.c" 1 INT #1 ; 0 "" 2 ; 272 "intexception.c" 1 INT #2 ; 0 "" 2 ; 273 "intexception.c" 1 INT #0xff ; 0 "" 2 ; 275 "intexception.c" 1 INT #0x7b ; 0 "" 2 mov.L #_ext, r5 movu.B [r5], r4 mov.L #.L4, r5 mov.L [r4,r5], r5 1:jmp r5 .section C,"a",@progbits .p2align 2 .balign 4 .balign 4 .L4: .long .L2 .long .L3 .long .L5
.L5: ; 277 "intexception.c" 1 INT #2 ; 0 "" 2 rts .L3: ; 277 "intexception.c" 1 INT #1 ; 0 "" 2 rts .L2: ; 277 "intexception.c" 1 INT #0 ; 0 "" 2 rts .L258: ; 277 "intexception.c" 1 INT #255 ; 0 "" 2 rts .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $
とするとまあまあ良いんじゃないでしょうか。
変数を使用した場合に展開されるのが嫌という場合には引数が定数か変数かで場合分けをして変数の場合には関数を呼び出す形にすれば良いと思います。
ちなみに、コメントアウトされていますが、
成る程、こういう書き方もできるのか。勉強になるな。
#define INTN(N)\ case N:\ __asm __volatile("INT #" #N "\n"); break; #define INTN5(N)\ INTN(N)\ INTN(N+1)\ INTN(N+2)\ INTN(N+3)\ INTN(N+4)\ #define INTN10(N)\ INTN5(N)\ INTN5(N+5)\ #define INTN50(N)\ INTN10(N)\ INTN10(N+10)\ INTN10(N+20)\ INTN10(N+30)\ INTN10(N+40) #define int_exception( num ) _int_exception_cpp_step2( num ) #define _int_exception_cpp_step2( num ) \ do { \ if (__builtin_constant_p(num)) { \ __asm __volatile("INT %0 \n"::"i"(num)); \ } else { \ switch (num) { \ INTN50(0) \ INTN50(50) \ INTN50(100) \ INTN50(150) \ INTN50(200) \ INTN5(250) \ INTN(255) \ default: \ __asm __volatile("INT #255\n"); break; \ } \ } \ } while (0);
自己書き換えコードで行けるのかな?
$ cat -n intexception.c 1 #include 2 3 #define int_exception( num ) _int_exception_cpp_step2( num ) 4 #define _int_exception_cpp_step2( num ) \ 5 do { \ 6 if (__builtin_constant_p(num)) { \ 7 __asm __volatile("INT %0 \n"::"i"(num)); \ 8 } else { \ 9 volatile uint8_t int_rts[] = {0x75, 0x60, num, 0x02}; \ 10 ((void (*)(void))int_rts)(); \ 11 } \ 12 } while (0); 13 14 void hoge(void) 15 { 16 int_exception(0); 17 int_exception(1); 18 int_exception(2); 19 int_exception(255); 20 int num = 123; 21 int_exception(num); 22 extern int ext; 23 int_exception(ext); 24 } $ rx-elf-gcc -Wall -Wextra -O2 intexception.c -S -o - .file "intexception.c" .section P,"ax" .global _hoge .type _hoge, @function _hoge: sub #4, r0 ; 16 "intexception.c" 1 INT #0 ; 0 "" 2 ; 17 "intexception.c" 1 INT #1 ; 0 "" 2 ; 18 "intexception.c" 1 INT #2 ; 0 "" 2 ; 19 "intexception.c" 1 INT #0xff ; 0 "" 2 ; 21 "intexception.c" 1 INT #0x7b ; 0 "" 2 mov.L #_ext, r5 movu.B [r5], r5 shll #16, r5 or #0x2006075, r5 mov.L r5, [r0] jsr r0 rtsd #4 .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $
fujitaさん、こんにちは。NoMaYです。アドバイス、どうも有難う御座います。デフォルトで変数時に自己書き換えコード、オプションで変数時に関数呼び出しコード、いずれも定数時は__builtin_rx_int()関数、としてみようと思います。オプションを用意する理由は、自己書き換えコードをスタック上で実行する方式はリエントラント性の点から良いと思ったのですが、以前にメモリプロテクションユニットに関して色々と投稿した身としては、このことでスタック領域全域に実行許可属性を付けないといけなくなってしまうのが気になってしまったからです。あと、コードを書いて気付いたのですが、そういえば__builtin_rx_int()関数があるのだから素朴に使えば良いよな、と我ながら思いました。今、こんな感じに書いています。
#ifdef DONT_EXECUTE_RX_INT_INSTRUCTION_ON_STACKvoid int_exception_switch_case_function(signed long num);#define int_exception(num) \do { \ if (__builtin_constant_p(num)) { \ __builtin_rx_int(num); \ } else { \ int_exception_switch_case_function(num); \ } \} while (0)#else /* DONT_EXECUTE_RX_INT_INSTRUCTION_ON_STACK */#define int_exception(num) \do { \ if (__builtin_constant_p(num)) { \ __builtin_rx_int(num); \ } else { \ unsigned char int_rts[] = {0x75, 0x60, num, 0x02}; \ ((void (*)(void*))int_rts)(int_rts); \ } \} while (0)#endif /* DONT_EXECUTE_RX_INT_INSTRUCTION_ON_STACK */
こんにちは。NoMaYです。試しにCCRXmachine2.hとCCRXmachine2.c(追加した理由は前の投稿にて説明)と確認用コードを書いてみました。CCRXmachine2.h
/* License: The MIT License will be used. https://opensource.org/licenses/MIT */ /* Docments: https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html and https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html https://gcc.gnu.org/onlinedocs/gcc/Basic-Asm.html https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html (https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html) https://gcc.gnu.org/onlinedocs/gcc/Constraints.html https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html https://gcc.gnu.org/onlinedocs/gcc/Explicit-Register-Variables.html https://gcc.gnu.org/onlinedocs/gcc/Size-of-an-asm.html and https://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html */ /* Use switch case function instead of RX INT instruction execution on stack. #define DONT_EXECUTE_RX_INT_INSTRUCTION_ON_STACK */ #ifndef CCRXMACHINE2_H #define CCRXMACHINE2_H static __inline__ signed long max(signed long data1, signed long data2) __attribute__((always_inline)); static __inline__ signed long max(signed long data1, signed long data2) { /* CC-RX V2.03 MAX R2, R1 RTS */ __asm__ volatile ( /* AssemblerTemplate */ "MAX %[R2], %[R1]" : /* OutputOperands */ [R1] "+r" (data1) : /* InputOperands */ [R2] "r" (data2) ); return data1; /* GNURX 2018q1 16 0000 FC 13 21 MAX r2, r1 22 0003 02 rts */ } static __inline__ signed long min(signed long data1, signed long data2) __attribute__((always_inline)); static __inline__ signed long min(signed long data1, signed long data2) { /* CC-RX V2.03 MIN R2, R1 RTS */ __asm__ volatile ( /* AssemblerTemplate */ "MIN %[R2], %[R1]" : /* OutputOperands */ [R1] "+r" (data1) : /* InputOperands */ [R2] "r" (data2) ); return data1; /* GNURX 2018q1 35 0004 FC 17 21 MIN r2, r1 41 0007 02 rts */ } static __inline__ signed long revl(signed long data) __attribute__((always_inline)); static __inline__ signed long revl(signed long data) { /* CC-RX V2.03 REVL R1, R1 RTS */ __asm__ volatile ( /* AssemblerTemplate */ "REVL %[R1], %[R1]" : /* OutputOperands */ [R1] "+r" (data) ); return data; /* GNURX 2018q1 54 0008 FD 67 11 REVL r1, r1 60 000b 02 rts */ } static __inline__ signed long revw(signed long data) __attribute__((always_inline)); static __inline__ signed long revw(signed long data) { /* CC-RX V2.03 REVW R1, R1 RTS */ __asm__ volatile ( /* AssemblerTemplate */ "REVW %[R1], %[R1]" : /* OutputOperands */ [R1] "+r" (data) ); return data; /* GNURX 2018q1 73 000c FD 65 11 REVW r1, r1 79 000f 02 rts */ } 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 */ } 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 */ } static __inline__ long long rmpaw(long long init, unsigned long count, short *addr1, short *addr2) __attribute__((always_inline)); static __inline__ long long rmpaw(long long init, unsigned long count, short *addr1, short *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.W MOV.L R5, R2 MOV.L R4, R1 RTSD #04H, R6-R6 */ register short *r1 __asm("r1") = addr1; register short *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.W" : /* OutputOperands */ "+r" (r5r4), "+r" (r6) : /* InputOperands */ "X" (r1), "X" (r2), "X" (r3) ); return r5r4; /* GNURX 2018q1 151 0033 7E A6 push.l r6 153 0035 60 40 sub #4, r0 156 0037 EF 25 mov.L r2, r5 157 0039 EF 1E mov.L r1, r14 162 003b EF 41 mov.L r4, r1 165 003d A8 8A mov.L 12[r0], r2 168 003f EF E4 mov.L r14, r4 171 0041 FD BF 56 shar #31, r5, r6 174 0044 7F 8D RMPA.W 179 0046 EF 41 mov.L r4, r1 181 0048 EF 52 mov.L r5, r2 182 004a 3F 66 02 rtsd #8, r6-r6 */ } static __inline__ long long rmpal(long long init, unsigned long count, long *addr1, long *addr2) __attribute__((always_inline)); static __inline__ long long rmpal(long long init, unsigned long count, long *addr1, long *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.L MOV.L R5, R2 MOV.L R4, R1 RTSD #04H, R6-R6 */ register long *r1 __asm("r1") = addr1; register long *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.L" : /* OutputOperands */ "+r" (r5r4), "+r" (r6) : /* InputOperands */ "X" (r1), "X" (r2), "X" (r3) ); return r5r4; /* GNURX 2018q1 191 004d 7E A6 push.l r6 193 004f 60 40 sub #4, r0 196 0051 EF 25 mov.L r2, r5 197 0053 EF 1E mov.L r1, r14 202 0055 EF 41 mov.L r4, r1 205 0057 A8 8A mov.L 12[r0], r2 208 0059 EF E4 mov.L r14, r4 211 005b FD BF 56 shar #31, r5, r6 214 005e 7F 8E RMPA.L 219 0060 EF 41 mov.L r4, r1 221 0062 EF 52 mov.L r5, r2 222 0064 3F 66 02 rtsd #8, r6-r6 */ } static __inline__ long rolc(unsigned long data) __attribute__((always_inline)); static __inline__ long rolc(unsigned long data) { /* CC-RX V2.03 ROLC R1 RTS */ __asm__ volatile ( /* AssemblerTemplate */ "ROLC %[R1]" : /* OutputOperands */ [R1] "+r" (data) ); return data; /* GNURX 2018q1 235 0067 7E 51 ROLC r1 241 0069 02 rts */ } static __inline__ long rorc(unsigned long data) __attribute__((always_inline)); static __inline__ long rorc(unsigned long data) { /* CC-RX V2.03 RORC R1 RTS */ __asm__ volatile ( /* AssemblerTemplate */ "RORC %[R1]" : /* OutputOperands */ [R1] "+r" (data) ); return data; /* GNURX 2018q1 254 006a 7E 41 RORC r1 260 006c 02 rts */ } static __inline__ long rotl(unsigned long data, unsigned long num) __attribute__((always_inline)); static __inline__ long rotl(unsigned long data, unsigned long num) { /* CC-RX V2.03 ROTL R2, R1 RTS */ __asm__ volatile ( /* AssemblerTemplate */ "ROTL %[R2], %[R1]" : /* OutputOperands */ [R1] "+r" (data) : /* InputOperands */ [R2] "r" (num) ); return data; /* GNURX 2018q1 292 0071 FD 64 21 ROTR r2, r1 298 0074 02 rts */ } static __inline__ long rotr(unsigned long data, unsigned long num) __attribute__((always_inline)); static __inline__ long rotr(unsigned long data, unsigned long num) { /* CC-RX V2.03 ROTR R2, R1 RTS */ __asm__ volatile ( /* AssemblerTemplate */ "ROTR %[R2], %[R1]" : /* OutputOperands */ [R1] "+r" (data) : /* InputOperands */ [R2] "r" (num) ); return data; /* GNURX 2018q1 292 0071 FD 64 21 ROTR r2, r1 298 0074 02 rts */ } #ifndef brk static __inline__ void brk(void) __attribute__((always_inline)); static __inline__ void brk(void) { /* CC-RX V2.03 BRK RTS */ __asm__ volatile ( /* AssemblerTemplate */ "BRK" : /* OutputOperands */ /* No outputs. */ ); return; /* GNURX 2018q1 310 0075 00 BRK 312 0076 02 rts */ } #endif /* #ifndef brk */ #ifdef DONT_EXECUTE_RX_INT_INSTRUCTION_ON_STACK void int_exception_switch_case_function(signed long num); #if 1 #define int_exception(num) \ do { \ if (__builtin_constant_p(num)) { \ __builtin_rx_int(num); \ } else { \ int_exception_switch_case_function(num); \ } \ } while (0) #else #define int_exception(num) \ do { \ if (__builtin_constant_p(num)) { \ __asm__ volatile \ ( \ /* AssemblerTemplate */ \ "INT %[NUM]" \ : /* OutputOperands */ \ /* No outputs. */ \ : /* InputOperands */ \ [NUM] "i" (num) \ ); \ } else { \ int_exception_switch_case_function(num); \ } \ } while (0) #endif #else /* DONT_EXECUTE_RX_INT_INSTRUCTION_ON_STACK */ #if 1 #define int_exception(num) \ do { \ if (__builtin_constant_p(num)) { \ __builtin_rx_int(num); \ } else { \ unsigned char int_rts[] = {0x75, 0x60, num, 0x02}; \ ((void (*)(void*))int_rts)(int_rts); \ } \ } while (0) #else #define int_exception(num) \ do { \ if (__builtin_constant_p(num)) { \ __asm__ volatile \ ( \ /* AssemblerTemplate */ \ "INT %[NUM]" \ : /* OutputOperands */ \ /* No outputs. */ \ : /* InputOperands */ \ [NUM] "i" (num) \ ); \ } else { \ unsigned char int_rts[] = {0x75, 0x60, num, 0x02}; \ ((void (*)(void*))int_rts)(int_rts); \ } \ } while (0) #endif #endif /* DONT_EXECUTE_RX_INT_INSTRUCTION_ON_STACK */ #ifndef wait static __inline__ void wait(void) __attribute__((always_inline)); static __inline__ void wait(void) { /* CC-RX V2.03 WAIT RTS */ __asm__ volatile ( /* AssemblerTemplate */ "WAIT" : /* OutputOperands */ /* No outputs. */ ); return; /* GNURX 2018q1 372 0092 7F 96 WAIT 374 0094 02 rts */ } #endif /* #ifndef wait */ #ifndef nop static __inline__ void nop(void) __attribute__((always_inline)); static __inline__ void nop(void) { /* CC-RX V2.03 NOP RTS */ __asm__ volatile ( /* AssemblerTemplate */ "NOP" : /* OutputOperands */ /* No outputs. */ ); return; /* GNURX 2018q1 388 0095 03 NOP 390 0096 02 rts */ } #endif /* #ifndef nop */ static __inline__ void set_ipl(signed long level) __attribute__((always_inline)); static __inline__ void set_ipl(signed long level) { /* CC-RX V2.03 MVFC PSW, R14 SHLL #1CH, R1 SHLR #04H, R1 AND #0F0FFFFFFH, R14 OR R14, R1 MVTC R1, PSW RTS */ signed long temp; __asm__ volatile ( /* AssemblerTemplate */ "MVFC PSW, %[R14]\n\t" "SHLL #0x1C, %[R1]\n\t" "SHLR #0x04, %[R1]\n\t" "AND #0xF0FFFFFF, %[R14]\n\t" "OR %[R14], %[R1]\n\t" "MVTC %[R1], PSW" : /* OutputOperands */ [R1] "+r" (level), [R14] "=r" (temp) ); return; /* GNURX 2018q1 405 0097 FD 6A 05 MVFC PSW, r5 406 009a 6D C1 SHLL #0x1C, r1 407 009c 68 41 SHLR #0x04, r1 408 009e 74 25 FF FF FF F0 AND #0xF0FFFFFF, r5 409 00a4 57 51 OR r5, r1 410 00a6 FD 68 10 MVTC r1, PSW 413 00a9 02 rts */ } static __inline__ unsigned char get_ipl(void) __attribute__((always_inline)); static __inline__ unsigned char get_ipl(void) { /* CC-RX V2.03 MVFC PSW, R14 REVL R14, R1 AND #0FH, R1 RTS */ signed long temp; unsigned char level; __asm__ volatile ( /* AssemblerTemplate */ "MVFC PSW, %[R14]\n\t" "REVL %[R14], %[R1]\n\t" "AND #0x0F, %[R1]" : /* OutputOperands */ [R14] "=r" (temp), [R1] "=r" (level) ); return level; /* GNURX 2018q1 427 00aa FD 6A 05 MVFC PSW, r5 428 00ad FD 67 51 REVL r5, r1 429 00b0 64 F1 AND #0x0F, r1 435 00b2 5B 11 movu.B r1, r1 436 00b4 02 rts */ } static __inline__ void set_psw(unsigned long data) __attribute__((always_inline)); static __inline__ void set_psw(unsigned long data) { /* CC-RX V2.03 MVTC R1, PSW RTS */ __asm__ volatile ( /* AssemblerTemplate */ "MVTC %[R1], PSW" : /* OutputOperands */ /* No outputs. */ : /* InputOperands */ [R1] "r" (data) ); return; /* GNURX 2018q1 449 00b5 FD 68 10 MVTC r1, PSW 451 00b8 02 rts */ } static __inline__ unsigned long get_psw(void) __attribute__((always_inline)); static __inline__ unsigned long get_psw(void) { /* CC-RX V2.03 MVFC PSW, R1 RTS */ unsigned long data; __asm__ volatile ( /* AssemblerTemplate */ "MVFC PSW, %[R1]" : /* OutputOperands */ [R1] "=r" (data) ); return data; /* GNURX 2018q1 465 00b9 FD 6A 01 MVFC PSW, r1 471 00bc 02 rts */ } static __inline__ void set_fpsw(unsigned long data) __attribute__((always_inline)); static __inline__ void set_fpsw(unsigned long data) { /* CC-RX V2.03 MVTC R1, FPSW RTS */ __asm__ volatile ( /* AssemblerTemplate */ "MVTC %[R1], FPSW" : /* OutputOperands */ /* No outputs. */ : /* InputOperands */ [R1] "r" (data) ); return; /* GNURX 2018q1 484 00bd FD 68 13 MVTC r1, FPSW 486 00c0 02 rts */ } static __inline__ unsigned long get_fpsw(void) __attribute__((always_inline)); static __inline__ unsigned long get_fpsw(void) { /* CC-RX V2.03 MVFC FPSW, R1 RTS */ unsigned long data; __asm__ volatile ( /* AssemblerTemplate */ "MVFC FPSW, %[R1]" : /* OutputOperands */ [R1] "=r" (data) ); return data; /* GNURX 2018q1 500 00c1 FD 6A 31 MVFC FPSW, r1 506 00c4 02 rts */ } static __inline__ void set_usp(void *data) __attribute__((always_inline)); static __inline__ void set_usp(void *data) { /* CC-RX V2.03 MVTC R1, USP RTS */ __asm__ volatile ( /* AssemblerTemplate */ "MVTC %[R1], USP" : /* OutputOperands */ /* No outputs. */ : /* InputOperands */ [R1] "r" (data) ); return; /* GNURX 2018q1 519 00c5 FD 68 12 MVTC r1, USP 521 00c8 02 rts */ } static __inline__ void *get_usp(void) __attribute__((always_inline)); static __inline__ void *get_usp(void) { /* CC-RX V2.03 MVFC USP, R1 RTS */ void *data; __asm__ volatile ( /* AssemblerTemplate */ "MVFC USP, %[R1]" : /* OutputOperands */ [R1] "=r" (data) ); return data; /* GNURX 2018q1 535 00c9 FD 6A 21 MVFC USP, r1 541 00cc 02 rts */ } static __inline__ void set_isp(void *data) __attribute__((always_inline)); static __inline__ void set_isp(void *data) { /* CC-RX V2.03 MVTC R1, ISP RTS */ __asm__ volatile ( /* AssemblerTemplate */ "MVTC %[R1], ISP" : /* OutputOperands */ /* No outputs. */ : /* InputOperands */ [R1] "r" (data) ); return; /* GNURX 2018q1 554 00cd FD 68 1A MVTC r1, ISP 556 00d0 02 rts */ } static __inline__ void *get_isp(void) __attribute__((always_inline)); static __inline__ void *get_isp(void) { /* CC-RX V2.03 MVFC ISP, R1 RTS */ void *data; __asm__ volatile ( /* AssemblerTemplate */ "MVFC ISP, %[R1]" : /* OutputOperands */ [R1] "=r" (data) ); return data; /* GNURX 2018q1 570 00d1 FD 6A A1 MVFC ISP, r1 576 00d4 02 rts */ } static __inline__ void set_intb(void *data) __attribute__((always_inline)); static __inline__ void set_intb(void *data) { /* CC-RX V2.03 MVTC R1, INTB RTS */ __asm__ volatile ( /* AssemblerTemplate */ "MVTC %[R1], INTB" : /* OutputOperands */ /* No outputs. */ : /* InputOperands */ [R1] "r" (data) ); return; /* GNURX 2018q1 589 00d5 FD 68 1C MVTC r1, INTB 591 00d8 02 rts */ } static __inline__ void *get_intb(void) __attribute__((always_inline)); static __inline__ void *get_intb(void) { /* CC-RX V2.03 MVFC INTB, R1 RTS */ void *data; __asm__ volatile ( /* AssemblerTemplate */ "MVFC INTB, %[R1]" : /* OutputOperands */ [R1] "=r" (data) ); return data; /* GNURX 2018q1 605 00d9 FD 6A C1 MVFC INTB, r1 611 00dc 02 rts */ } static __inline__ void set_bpsw(unsigned long data) __attribute__((always_inline)); static __inline__ void set_bpsw(unsigned long data) { /* CC-RX V2.03 MVTC R1, BPSW RTS */ __asm__ volatile ( /* AssemblerTemplate */ "MVTC %[R1], BPSW" : /* OutputOperands */ /* No outputs. */ : /* InputOperands */ [R1] "r" (data) ); return; /* GNURX 2018q1 624 00dd FD 68 18 MVTC r1, BPSW 626 00e0 02 rts */ } static __inline__ unsigned long get_bpsw(void) __attribute__((always_inline)); static __inline__ unsigned long get_bpsw(void) { /* CC-RX V2.03 MVFC BPSW, R1 RTS */ unsigned long data; __asm__ volatile ( /* AssemblerTemplate */ "MVFC BPSW, %[R1]" : /* OutputOperands */ [R1] "=r" (data) ); return data; /* GNURX 2018q1 640 00e1 FD 6A 81 MVFC BPSW, r1 646 00e4 02 rts */ } static __inline__ void set_bpc(void *data) __attribute__((always_inline)); static __inline__ void set_bpc(void *data) { /* CC-RX V2.03 MVTC R1, BPC RTS */ __asm__ volatile ( /* AssemblerTemplate */ "MVTC %[R1], BPC" : /* OutputOperands */ /* No outputs. */ : /* InputOperands */ [R1] "r" (data) ); return; /* GNURX 2018q1 659 00e5 FD 68 19 MVTC r1, BPC 661 00e8 02 rts */ } static __inline__ void *get_bpc(void) __attribute__((always_inline)); static __inline__ void *get_bpc(void) { /* CC-RX V2.03 MVFC BPC, R1 RTS */ void *data; __asm__ volatile ( /* AssemblerTemplate */ "MVFC BPC, %[R1]" : /* OutputOperands */ [R1] "=r" (data) ); return data; /* GNURX 2018q1 675 00e9 FD 6A 91 MVFC BPC, r1 681 00ec 02 rts */ } static __inline__ void set_fintv(void *data) __attribute__((always_inline)); static __inline__ void set_fintv(void *data) { /* CC-RX V2.03 MVTC R1, FINTV RTS */ __asm__ volatile ( /* AssemblerTemplate */ "MVTC %[R1], FINTV" : /* OutputOperands */ /* No outputs. */ : /* InputOperands */ [R1] "r" (data) ); return; /* GNURX 2018q1 694 00ed FD 68 1B MVTC r1, FINTV 696 00f0 02 rts */ } static __inline__ void *get_fintv(void) __attribute__((always_inline)); static __inline__ void *get_fintv(void) { /* CC-RX V2.03 MVFC FINTV, R1 RTS */ void *data; __asm__ volatile ( /* AssemblerTemplate */ "MVFC FINTV, %[R1]" : /* OutputOperands */ [R1] "=r" (data) ); return data; /* GNURX 2018q1 710 00f1 FD 6A B1 MVFC FINTV, r1 716 00f4 02 rts */ } static __inline__ signed long long emul(signed long data1, signed long data2) __attribute__((always_inline)); static __inline__ signed long long emul(signed long data1, signed long data2) { /* CC-RX V2.03 MOV.L R1, R4 EMUL R2, R4 MOV.L R5, R2 MOV.L R4, R1 RTS */ return (signed long long)data1 * data2; /* GNURX 2018q1 728 00f5 FC 1B 12 emul r1, r2 733 00f8 EF 21 mov.L r2, r1 735 00fa EF 32 mov.L r3, r2 736 00fc 02 rts */ } static __inline__ unsigned long long emulu(unsigned long data1, unsigned long data2) __attribute__((always_inline)); static __inline__ unsigned long long emulu(unsigned long data1, unsigned long data2) { /* CC-RX V2.03 MOV.L R1, R4 EMULU R2, R4 MOV.L R5, R2 MOV.L R4, R1 RTS */ return (unsigned long long)data1 * data2; /* GNURX 2018q1 748 00fd FC 1F 12 emulu r1, r2 753 0100 EF 21 mov.L r2, r1 755 0102 EF 32 mov.L r3, r2 756 0104 02 rts */ } static __inline__ void chg_pmusr(void) __attribute__((always_inline)); static __inline__ void chg_pmusr(void) { /* CC-RX V2.03 MVFC PSW, R14 BTST #14H, R14 BNE L48 L47: ; entry OR #00100000H, R14 PUSH.L R14 L49: MVFC PC, R14 ADD #L48-L49, R14 PUSH.L R14 RTE L48: ; entry RTS */ signed long temp; __asm__ volatile ( /* AssemblerTemplate */ "MVFC PSW, %[R14]\n\t" "BTST #0x14, %[R14]\n\t" "BNE 3f\n" "1:\n\t" "OR #0x00100000, %[R14]\n\t" "PUSH.L %[R14]\n" "2:\n\t" "MVFC PC, %[R14]\n\t" "ADD #3f-2b, %[R14]\n\t" "PUSH.L %[R14]\n\t" "RTE\n" "3:" : /* OutputOperands */ [R14] "=r" (temp) ); return; /* GNURX 2018q1 768 0105 FD 6A 05 MVFC PSW, r5 769 0108 7D 45 BTST #0x14, r5 770 010a 21 13 BNE 3f 771 1: 772 010c 77 35 00 00 10 OR #0x00100000, r5 773 0111 7E A5 PUSH.L r5 774 2: 775 0113 FD 6A 15 MVFC PC, r5 776 0116 71 55 0A ADD #3f-2b, r5 777 0119 7E A5 PUSH.L r5 778 011b 7F 95 RTE 779 3: 783 011d 02 rts */ } static __inline__ void set_acc(signed long long data) __attribute__((always_inline)); static __inline__ void set_acc(signed long long data) { /* CC-RX V2.03 MVTACLO R1 MVTACHI R2 RTS */ signed long temp1 = (signed long)data; signed long temp2 = (signed long)(data >> 32); __asm__ volatile ( /* AssemblerTemplate */ "MVTACLO R1\n\t" "MVTACHI R2" : /* OutputOperands */ /* No outputs. */ : /* InputOperands */ [R1] "r" (temp1), [R2] "r" (temp2) ); return; /* GNURX 2018q1 797 011e FD 17 11 MVTACLO R1 798 0121 FD 17 02 MVTACHI R2 800 0124 02 rts */ } static __inline__ signed long long get_acc(void) __attribute__((always_inline)); static __inline__ signed long long get_acc(void) { /* CC-RX V2.03 MVFACMI R1 SHLL #10H, R1 MVFACHI R2 RTS */ unsigned long temp1; unsigned long temp2; __asm__ volatile ( /* AssemblerTemplate */ "MVFACMI R1\n\t" "SHLL #0x10, R1\n\t" "MVFACHI R2" : /* OutputOperands */ [R1] "=r" (temp1), [R2] "=r" (temp2) ); return (unsigned long long)((((unsigned long long)temp2) << 32) | temp1); /* GNURX 2018q1 813 0125 FD 1F 21 MVFACMI R1 814 0128 6D 01 SHLL #0x10, R1 815 012a FD 1F 02 MVFACHI R2 817 012d 02 rts */ } static __inline__ void setpsw_i(void) __attribute__((always_inline)); static __inline__ void setpsw_i(void) { /* CC-RX V2.03 SETPSW I RTS */ __asm__ volatile ( /* AssemblerTemplate */ "SETPSW I" : /* OutputOperands */ /* No outputs. */ ); return; /* GNURX 2018q1 829 012e 7F A8 SETPSW I 831 0130 02 rts */ } static __inline__ void clrpsw_i(void) __attribute__((always_inline)); static __inline__ void clrpsw_i(void) { /* CC-RX V2.03 CLRPSW I RTS */ __asm__ volatile ( /* AssemblerTemplate */ "CLRPSW I" : /* OutputOperands */ /* No outputs. */ ); return; /* GNURX 2018q1 845 0131 7F B8 CLRPSW I 847 0133 02 rts */ } static __inline__ long macl(short *data1, short *data2, unsigned long count) __attribute__((always_inline)); static __inline__ long macl(short *data1, short *data2, unsigned long count) { /* CC-RX V2.03 CMP #00H, R3 MOV.L #00000000H, R14 MULLO R14, R14 BEQ L60 L55: ; entry BTST #00H, R3 BGEU L57 L56: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L56 BRA L60 L57: ; entry SUB #01H, R3 BEQ L59 L58: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L58 L59: ; entry MOV.W [R1], R14 MOV.W [R2], R5 MACLO R14, R5 L60: ; entry MVFACMI R1 RTS */ long temp1; long temp2; long result; __asm__ volatile ( /* AssemblerTemplate */ "CMP #0x00, %[R3]\n\t" "MOV.L #0x00000000, %[R14]\n\t" "MULLO %[R14], %[R14]\n\t" "BEQ 6f\n\t" "1:\n\t" "BTST #0x00, %[R3]\n\t" "BGEU 3f\n\t" "2:\n\t" "SUB #0x02, %[R3]\n\t" "MOV.L [%[R1]+], %[R14]\n\t" "MOV.L [%[R2]+], %[R5]\n\t" "MACLO %[R14], %[R5]\n\t" "MACHI %[R14], %[R5]\n\t" "BNE 2b\n\t" "BRA 6f\n\t" "3:\n\t" "SUB #0x01, %[R3]\n\t" "BEQ 5f\n\t" "4:\n\t" "SUB #0x02, %[R3]\n\t" "MOV.L [%[R1]+], %[R14]\n\t" "MOV.L [%[R2]+], %[R5]\n\t" "MACLO %[R14], %[R5]\n\t" "MACHI %[R14], %[R5]\n\t" "BNE 4b\n\t" "5:\n\t" "MOV.W [%[R1]], %[R14]\n\t" "MOV.W [%[R2]], %[R5]\n\t" "MACLO %[R14], %[R5]\n\t" "6:\n\t" "MVFACMI %[R99]" : /* OutputOperands */ [R5] "+r" (temp1), [R14] "+r" (temp2), [R99] "=r" (result) : /* InputOperands */ [R1] "r" (data1), [R2] "r" (data2), [R3] "r" (count) ); return result; /* GNURX 2018q1 859 0134 66 05 mov.L #0, r5 860 0136 EF 54 mov.L r5, r4 862 0138 61 03 CMP #0x00, r3 863 013a 66 04 MOV.L #0x00000000, r4 864 013c FD 01 44 MULLO r4, r4 865 013f 20 33 BEQ 6f 866 1: 867 0141 7C 03 BTST #0x00, r3 868 0143 22 14 BGEU 3f 869 2: 870 0145 60 23 SUB #0x02, r3 871 0147 FD 2A 14 MOV.L [r1+], r4 872 014a FD 2A 25 MOV.L [r2+], r5 873 014d FD 05 45 MACLO r4, r5 874 0150 FD 04 45 MACHI r4, r5 875 0153 21 F2 BNE 2b 876 0155 2E 1D BRA 6f 877 3: 878 0157 60 13 SUB #0x01, r3 879 0159 20 12 BEQ 5f 880 4: 881 015b 60 23 SUB #0x02, r3 882 015d FD 2A 14 MOV.L [r1+], r4 883 0160 FD 2A 25 MOV.L [r2+], r5 884 0163 FD 05 45 MACLO r4, r5 885 0166 FD 04 45 MACHI r4, r5 886 0169 21 F2 BNE 4b 887 5: 888 016b DC 14 MOV.W [r1], r4 889 016d DC 25 MOV.W [r2], r5 890 016f FD 05 45 MACLO r4, r5 891 6: 892 0172 FD 1F 21 MVFACMI r1 895 0175 02 rts */ } static __inline__ short macw1(short *data1, short *data2, unsigned long count) __attribute__((always_inline)); static __inline__ short macw1(short *data1, short *data2, unsigned long count) { /* CC-RX V2.03 CMP #00H, R3 MOV.L #00000000H, R14 MULLO R14, R14 BEQ L67 L62: ; entry BTST #00H, R3 BGEU L64 L63: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L63 BRA L67 L64: ; entry SUB #01H, R3 BEQ L66 L65: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L65 L66: ; entry MOV.W [R1], R14 MOV.W [R2], R5 MACLO R14, R5 L67: ; entry RACW #01H MVFACHI R1 RTS */ long temp1; long temp2; short result; __asm__ volatile ( /* AssemblerTemplate */ "CMP #0x00, %[R3]\n\t" "MOV.L #0x00000000, %[R14]\n\t" "MULLO %[R14], %[R14]\n\t" "BEQ 6f\n\t" "1:\n\t" "BTST #0x00, %[R3]\n\t" "BGEU 3f\n\t" "2:\n\t" "SUB #0x02, %[R3]\n\t" "MOV.L [%[R1]+], %[R14]\n\t" "MOV.L [%[R2]+], %[R5]\n\t" "MACLO %[R14], %[R5]\n\t" "MACHI %[R14], %[R5]\n\t" "BNE 2b\n\t" "BRA 6f\n\t" "3:\n\t" "SUB #0x01, %[R3]\n\t" "BEQ 5f\n\t" "4:\n\t" "SUB #0x02, %[R3]\n\t" "MOV.L [%[R1]+], %[R14]\n\t" "MOV.L [%[R2]+], %[R5]\n\t" "MACLO %[R14], %[R5]\n\t" "MACHI %[R14], %[R5]\n\t" "BNE 4b\n\t" "5:\n\t" "MOV.W [%[R1]], %[R14]\n\t" "MOV.W [%[R2]], %[R5]\n\t" "MACLO %[R14], %[R5]\n\t" "6:\n\t" "RACW #0x01\n\t" "MVFACMI %[R99]" : /* OutputOperands */ [R5] "+r" (temp1), [R14] "+r" (temp2), [R99] "=r" (result) : /* InputOperands */ [R1] "r" (data1), [R2] "r" (data2), [R3] "r" (count) ); return result; /* GNURX 2018q1 907 0176 66 05 mov.L #0, r5 908 0178 EF 54 mov.L r5, r4 910 017a 61 03 CMP #0x00, r3 911 017c 66 04 MOV.L #0x00000000, r4 912 017e FD 01 44 MULLO r4, r4 913 0181 20 33 BEQ 6f 914 1: 915 0183 7C 03 BTST #0x00, r3 916 0185 22 14 BGEU 3f 917 2: 918 0187 60 23 SUB #0x02, r3 919 0189 FD 2A 14 MOV.L [r1+], r4 920 018c FD 2A 25 MOV.L [r2+], r5 921 018f FD 05 45 MACLO r4, r5 922 0192 FD 04 45 MACHI r4, r5 923 0195 21 F2 BNE 2b 924 0197 2E 1D BRA 6f 925 3: 926 0199 60 13 SUB #0x01, r3 927 019b 20 12 BEQ 5f 928 4: 929 019d 60 23 SUB #0x02, r3 930 019f FD 2A 14 MOV.L [r1+], r4 931 01a2 FD 2A 25 MOV.L [r2+], r5 932 01a5 FD 05 45 MACLO r4, r5 933 01a8 FD 04 45 MACHI r4, r5 934 01ab 21 F2 BNE 4b 935 5: 936 01ad DC 14 MOV.W [r1], r4 937 01af DC 25 MOV.W [r2], r5 938 01b1 FD 05 45 MACLO r4, r5 939 6: 940 01b4 FD 18 00 RACW #0x01 941 01b7 FD 1F 21 MVFACMI r1 947 01ba DF 11 mov.W r1, r1 948 01bc 02 rts */ } static __inline__ short macw2(short *data1, short *data2, unsigned long count) __attribute__((always_inline)); static __inline__ short macw2(short *data1, short *data2, unsigned long count) { /* CC-RX V2.03 CMP #00H, R3 MOV.L #00000000H, R14 MULLO R14, R14 BEQ L74 L69: ; entry BTST #00H, R3 BGEU L71 L70: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L70 BRA L74 L71: ; entry SUB #01H, R3 BEQ L73 L72: ; entry SUB #02H, R3 MOV.L [R1+], R14 MOV.L [R2+], R5 MACLO R14, R5 MACHI R14, R5 BNE L72 L73: ; entry MOV.W [R1], R14 MOV.W [R2], R5 MACLO R14, R5 L74: ; entry RACW #02H MVFACHI R1 RTS */ long temp1; long temp2; short result; __asm__ volatile ( /* AssemblerTemplate */ "CMP #0x00, %[R3]\n\t" "MOV.L #0x00000000, %[R14]\n\t" "MULLO %[R14], %[R14]\n\t" "BEQ 6f\n\t" "1:\n\t" "BTST #0x00, %[R3]\n\t" "BGEU 3f\n\t" "2:\n\t" "SUB #0x02, %[R3]\n\t" "MOV.L [%[R1]+], %[R14]\n\t" "MOV.L [%[R2]+], %[R5]\n\t" "MACLO %[R14], %[R5]\n\t" "MACHI %[R14], %[R5]\n\t" "BNE 2b\n\t" "BRA 6f\n\t" "3:\n\t" "SUB #0x01, %[R3]\n\t" "BEQ 5f\n\t" "4:\n\t" "SUB #0x02, %[R3]\n\t" "MOV.L [%[R1]+], %[R14]\n\t" "MOV.L [%[R2]+], %[R5]\n\t" "MACLO %[R14], %[R5]\n\t" "MACHI %[R14], %[R5]\n\t" "BNE 4b\n\t" "5:\n\t" "MOV.W [%[R1]], %[R14]\n\t" "MOV.W [%[R2]], %[R5]\n\t" "MACLO %[R14], %[R5]\n\t" "6:\n\t" "RACW #02H\n\t" "MVFACMI %[R99]" : /* OutputOperands */ [R5] "+r" (temp1), [R14] "+r" (temp2), [R99] "=r" (result) : /* InputOperands */ [R1] "r" (data1), [R2] "r" (data2), [R3] "r" (count) ); return result; /* GNURX 2018q1 960 01bd 66 05 mov.L #0, r5 961 01bf EF 54 mov.L r5, r4 963 01c1 61 03 CMP #0x00, r3 964 01c3 66 04 MOV.L #0x00000000, r4 965 01c5 FD 01 44 MULLO r4, r4 966 01c8 20 33 BEQ 6f 967 1: 968 01ca 7C 03 BTST #0x00, r3 969 01cc 22 14 BGEU 3f 970 2: 971 01ce 60 23 SUB #0x02, r3 972 01d0 FD 2A 14 MOV.L [r1+], r4 973 01d3 FD 2A 25 MOV.L [r2+], r5 974 01d6 FD 05 45 MACLO r4, r5 975 01d9 FD 04 45 MACHI r4, r5 976 01dc 21 F2 BNE 2b 977 01de 2E 1D BRA 6f 978 3: 979 01e0 60 13 SUB #0x01, r3 980 01e2 20 12 BEQ 5f 981 4: 982 01e4 60 23 SUB #0x02, r3 983 01e6 FD 2A 14 MOV.L [r1+], r4 984 01e9 FD 2A 25 MOV.L [r2+], r5 985 01ec FD 05 45 MACLO r4, r5 986 01ef FD 04 45 MACHI r4, r5 987 01f2 21 F2 BNE 4b 988 5: 989 01f4 DC 14 MOV.W [r1], r4 990 01f6 DC 25 MOV.W [r2], r5 991 01f8 FD 05 45 MACLO r4, r5 992 6: 993 01fb FD 18 10 RACW #02H 994 01fe FD 1F 21 MVFACMI r1 1000 0201 DF 11 mov.W r1, r1 1001 0203 02 rts */ } static __inline__ void set_extb(void *data) __attribute__((always_inline)); static __inline__ void set_extb(void *data) { /* CC-RX V2.03 MVTC R1, EXTB RTS */ __asm__ volatile ( /* AssemblerTemplate */ "MVTC %[R1], EXTB" : /* OutputOperands */ /* No outputs. */ : /* InputOperands */ [R1] "r" (data) ); return; /* GNURX 2018q1 1014 0204 FD 68 1D MVTC r1, EXTB 1016 0207 02 rts */ } static __inline__ void *get_extb(void) __attribute__((always_inline)); static __inline__ void *get_extb(void) { /* CC-RX V2.03 MVFC EXTB, R1 RTS */ void *data; __asm__ volatile ( /* AssemblerTemplate */ "MVFC EXTB, %[R1]" : /* OutputOperands */ [R1] "=r" (data) ); return data; /* GNURX 2018q1 1030 0208 FD 6A D1 MVFC EXTB, r1 1036 020b 02 rts */ } #endif /* CCRXMACHINE2_H */
#define DONT_EXECUTE_RX_INT_INSTRUCTION_ON_STACK #ifdef DONT_EXECUTE_RX_INT_INSTRUCTION_ON_STACK #if 1 #define INTNUM(num)\ __builtin_rx_int(num) #else #define INTNUM(num)\ __asm__ volatile\ (\ /* AssemblerTemplate */\ "INT #" #num \ : /* OutputOperands */\ /* No outputs. */\ ) #endif #define INTN(N)\ case N:\ INTNUM(N);\ break; #define INTN5(N)\ INTN(N)\ INTN(N+1)\ INTN(N+2)\ INTN(N+3)\ INTN(N+4) #define INTN10(N)\ INTN5(N)\ INTN5(N+5) #define INTN50(N)\ INTN10(N)\ INTN10(N+10)\ INTN10(N+20)\ INTN10(N+30)\ INTN10(N+40) void int_exception_switch_case_function(signed long num); void int_exception_switch_case_function(signed long num) { switch(num) { INTN50(0) INTN50(50) INTN50(100) INTN50(150) INTN50(200) INTN5(250) INTN(255) default: INTNUM(255); } } #endif /* DONT_EXECUTE_RX_INT_INSTRUCTION_ON_STACK */
//#include "r_smc_entry.h" //#define DONT_EXECUTE_RX_INT_INSTRUCTION_ON_STACK #include "CCRXmachine2.h" signed long _max(signed long data1, signed long data2) { return max(data1, data2); } signed long _min(signed long data1, signed long data2) { return min(data1, data2); } unsigned long _revl(unsigned long data) { return revl(data); } unsigned long _revw(unsigned long data) { return revw(data); } void _xchg(signed long *data1, signed long *data2) { xchg(data1, data2); } long long _rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2) { return rmpab(init, count, addr1, addr2); } long long _rmpaw(long long init, unsigned long count, short *addr1, short *addr2) { return rmpaw(init, count, addr1, addr2); } long long _rmpal(long long init, unsigned long count, long *addr1, long *addr2) { return rmpal(init, count, addr1, addr2); } unsigned long _rolc(unsigned long data) { return rolc(data); } unsigned long _rorc(unsigned long data) { return rorc(data); } unsigned long _rotl(unsigned long data, unsigned long num) { return rotl(data, num); } unsigned long _rotr(unsigned long data, unsigned long num) { return rotr(data, num); } void _brk(void) { brk(); } void _int_exception(signed long num) { int_exception(num); } void _my_int_exception_0(void) { int_exception(0); } void _my_int_exception_255(void) { int_exception(255); } void _wait(void) { wait(); } void _nop(void) { nop(); } void _set_ipl(signed long level) { set_ipl(level); } unsigned char _get_ipl(void) { return get_ipl(); } void _set_psw(unsigned long data) { set_psw(data); } unsigned long _get_psw(void) { return get_psw(); } void _set_fpsw(unsigned long data) { set_fpsw(data); } unsigned long _get_fpsw(void) { return get_fpsw(); } void _set_usp(void *data) { set_usp(data); } void * _get_usp(void) { return get_usp(); } void _set_isp(void *data) { set_isp(data); } void * _get_isp(void) { return get_isp(); } void _set_intb(void *data) { set_intb(data); } void * _get_intb(void) { return get_intb(); } void _set_bpsw(unsigned long data) { set_bpsw(data); } unsigned long _get_bpsw(void) { return get_bpsw(); } void _set_bpc(void *data) { set_bpc(data); } void * _get_bpc(void) { return get_bpc(); } void _set_fintv(void *data) { set_fintv(data); } void * _get_fintv(void) { return get_fintv(); } signed long long _emul(signed long data1, signed long data2) { return emul(data1, data2); } unsigned long long _emulu(unsigned long data1, unsigned long data2) { return emulu(data1, data2); } void _chg_pmusr(void) { chg_pmusr(); } void _set_acc(signed long long data) { set_acc(data); } signed long long _get_acc(void) { return get_acc(); } void _setpsw_i(void) { setpsw_i(); } void _clrpsw_i(void) { clrpsw_i(); } long _macl(short *data1, short *data2, unsigned long count) { return macl(data1, data2, count); } short _macw1(short *data1, short *data2, unsigned long count) { return macw1(data1, data2, count); } short _macw2(short *data1, short *data2, unsigned long count) { return macw2(data1, data2, count); } void _set_extb(void *data) { set_extb(data); } void * _get_extb(void) { return get_extb(); } void main(void); void main(void) { nop(); chg_pmusr(); nop(); for (;;) ; }
fujitaさんほやです。
>> xchg関数1つならそれもアリなのですが、他の組み込み関数までヘッダに記述するのはムリがあるかと。>えっなんで??>> CCRXmachine.hの中で、マクロに書き換えられるものをマクロに、>マクロよりはインライン関数の方が良いのでは。
「関数本体をヘッダに」含めるのを嫌がる人は更に多いのでは。そもそもCCRXmachine.h/.cはCCRXの記述をできるだけ変更しないでGNURXに置き換えるためにあるのだから、関数名だけすげ替えれば済むものは、それで留めるべきだったと思います。xchg関数もその一つ。