こんにちは。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
GNURX の __builtin_rx_xchg() を確認してみましたが
$ cat -n xchgTest.c 1 extern int a, b; 2 3 void hoge(void) 4 { 5 __builtin_rx_xchg(&a, &b); 6 } $ rx-elf-gcc -v Using built-in specs. COLLECT_GCC=C:\Renesas\e2studio\GCC for Renesas RX 4.8.4.201801-GNURX-ELF\rx-elf\rx-elf\bin\rx-elf-gcc.exe COLLECT_LTO_WRAPPER=c:/renesas/e2studio/gcc\ for\ renesas\ rx\ 4.8.4.201801-gnurx-elf/rx-elf/rx-elf/bin/../libexec/gcc/rx-elf/4.8.4.201801-GNURX/lto-wrapper.exe Target: rx-elf Configured with: /builder/AutomatedBuilds/rx/builds/2018q1_RX_RC3/rx/source/gcc/configure --target=rx-elf --host=i586-mingw32msvc --enable-languages=c,c++ --disable-shared --with-newlib --enable-lto --enable-libssp --enable-plugins --enable-gold --disable-libstdcxx-pch --with-pkgversion=GCC_Build_20180316 --prefix=/builder/AutomatedBuilds/rx/builds/2018q1_RX_RC3/rx/rx_win Thread model: single gcc version 4.8.4.201801-GNURX (GCC_Build_20180316) $ rx-elf-gcc -O2 xchgTest.c -S -o - .file "xchgTest.c" .section P,"ax" .global _hoge .type _hoge, @function _hoge: mov.L #_a, r2 mov.L [r2], r3 mov.L #_b, r5 mov.L [r5], r4 mov.L r3, [r2] xchg r4, r3 mov.L r4, [r5] rts .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $
ちょっと排他制御には使えない感じですね。
こんにちは。NoMaYです。
fujita nozomu said:ちょっと排他制御には使えない感じですね。
#define bool _Bool#define false 0#define true 1typedef signed char int8_t;typedef unsigned char uint8_t;typedef signed short int16_t;typedef unsigned short uint16_t;typedef signed long int32_t;typedef unsigned long uint32_t;typedef signed long long int64_t;typedef unsigned long long uint64_t;typedef unsigned long size_t;/* By default modules will use global locks found in mcu_locks.c. If the user is using a RTOS and would rather use its locking mechanisms then they can change this macro. NOTE: If '1' is chosen for this macro then the user must also change the next macro 'BSP_CFG_USER_LOCKING_TYPE'. 0 = Use default locking (non-RTOS) 1 = Use user defined locking mechanism. */#define BSP_CFG_USER_LOCKING_ENABLED (0)/* If the user decides to use their own locking mechanism with FIT modules then they will need to redefine the typedef that is used for the locks. If the user is using a RTOS then they would likely redefine the typedef to be a semaphore/mutex type of their RTOS. Use the macro below to set the type that will be used for the locks. NOTE: If BSP_CFG_USER_LOCKING_ENABLED == 0 then this typedef is ignored. NOTE: Do not surround the type with parentheses '(' ')'.*/#define BSP_CFG_USER_LOCKING_TYPE bsp_lock_ttypedef enum { BSP_LOCK_BSC = 0, BSP_LOCK_CAC, BSP_LOCK_CAN0, BSP_LOCK_CAN1, BSP_LOCK_CMT, BSP_LOCK_CMT0, BSP_LOCK_CMT1, BSP_LOCK_CMT2, BSP_LOCK_CMT3, /* 略 */ BSP_LOCK_GLCDC, BSP_LOCK_DRW2D, BSP_NUM_LOCKS //This entry is not a valid lock. It is used for sizing g_bsp_Locks[] array below. Do not touch!} mcu_lock_t;typedef struct{ /* The actual lock. int32_t is used because this is what the xchg() instruction takes as parameters. */ int32_t lock; /* Could add a ID for locking and unlocking. In this could protect against any function being able to unlock. */} bsp_lock_t;BSP_CFG_USER_LOCKING_TYPE g_bsp_Locks[BSP_NUM_LOCKS]; bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){#if BSP_CFG_USER_LOCKING_ENABLED == 0 bool ret = false; /* Variable used in trying to acquire lock. Using the xchg instruction makes this atomic */ int32_t is_locked = true; /* This example uses the RX MCU's atomic xchg() instruction. plock->lock is the lock we are trying to reserve. The way this works is that 'is_locked' gets the value of the plock->lock and plock->lock gets the value of 'is_locked' which we just set to 'true'. Basically this is an atomic 'swap' command. If the lock had not yet been reserved then its value would be 'false' and after the xchg() instruction finished 'is_locked' would have 'false'. If it had already been reserved then 'is_locked' would have 'true' after the xchg() instruction. Since plock->lock was already 'true' and we just set it back to 'true' everything is ok. To see if we reserved the lock we just need to check the value of 'is_locked' after this instruction finishes. */ /* Try to acquire semaphore to obtain lock */ __builtin_rx_xchg((int *)&is_locked, (int *)&plock->lock); /* xchg(&is_locked, &plock->lock); */ /* Check to see if semaphore was successfully taken */ if (is_locked == false) { /* Lock obtained, return success. */ ret = true; } else { /* Lock was not obtained, another task already has it. */ } return ret; #else /* User is going to handle the locking themselves. */ return BSP_CFG_USER_LOCKING_SW_LOCK_FUNCTION(plock);#endif} /* End of function R_BSP_SoftwareLock() */bool R_BSP_HardwareLock (mcu_lock_t const hw_index){#if BSP_CFG_USER_LOCKING_ENABLED == 0 /* Pass actual lock to software lock function. */ return R_BSP_SoftwareLock(&g_bsp_Locks[hw_index]);#else /* User is going to handle the locking themselves. */ return BSP_CFG_USER_LOCKING_HW_LOCK_FUNCTION(hw_index);#endif} /* End of function R_BSP_HardwareLock() */#define CMT_RX_NUM_CHANNELS 4/*static*/ bool cmt_find_channel (uint32_t * channel){ bool channel_found = false; uint32_t i; /* Look for an available channel. */ for (i = 0; i < CMT_RX_NUM_CHANNELS; i++) {#if BSP_CFG_RTOS_USED == 0 // Non-OS#elif BSP_CFG_RTOS_USED == 1 // FreeRTOS if (i == BSP_CFG_RTOS_SYSTEM_TIMER) { /* Found CMT channel is being used for RTOS. */ continue; }#elif BSP_CFG_RTOS_USED == 2 // SEGGER embOS#elif BSP_CFG_RTOS_USED == 3 // Micrium MicroC/OS#elif BSP_CFG_RTOS_USED == 4 // Renesas RI600V4 & RI600PX#endif if (true == R_BSP_HardwareLock((mcu_lock_t)(BSP_LOCK_CMT0 + i))) { /* Channel found. */ *channel = i; channel_found = true; break; } } return channel_found;}
以下のリストの赤字箇所でセマフォのロックに使用出来る命令列が生成されていた
1035 .global _R_BSP_SoftwareLock 1037 _R_BSP_SoftwareLock: 1041 020c 60 40 sub #4, r0 1045 020e F8 06 01 mov.L #1, [r0] 1047 0211 EC 05 mov.L [r0], r5 1048 0213 06 A0 10 15 xchg [r1].L, r5 1049 0217 E3 05 mov.L r5, [r0] 1051 0219 EC 01 mov.L [r0], r1 1054 021b 61 01 cmp #0, r1 1055 021d FC DB 10 sceq.L r1 1057 0220 67 01 rtsd #4 1060 .global _R_BSP_HardwareLock 1062 _R_BSP_HardwareLock: 1066 0222 60 40 sub #4, r0 1072 0224 F8 06 01 mov.L #1, [r0] 1076 0227 6C 21 shll #2, r1 1081 0229 EC 05 mov.L [r0], r5 1085 022b 70 11 00 00 00 00 add #_g_bsp_Locks, r1 1090 0231 06 A0 10 15 xchg [r1].L, r5 1091 0235 E3 05 mov.L r5, [r0] 1093 0237 EC 01 mov.L [r0], r1 1098 0239 61 01 cmp #0, r1 1099 023b FC DB 10 sceq.L r1 1101 023e 67 01 rtsd #4 1104 .global _cmt_find_channel 1106 _cmt_find_channel: 1110 0240 60 40 sub #4, r0 1113 0242 FB 32 00 00 00 00 mov.L #_g_bsp_Locks+20, r3 1115 0248 66 04 mov.L #0, r4 1117 .balign 8,3,4 1123 024a F8 06 01 mov.L #1, [r0] 1125 024d EC 05 mov.L [r0], r5 1126 024f 06 A0 10 35 xchg [r3].L, r5 1127 0253 E3 05 mov.L r5, [r0] 1129 0255 EC 05 mov.L [r0], r5 1130 0257 61 05 cmp #0, r5 1131 0259 19 bne .L67 1137 025a E3 14 mov.L r4, [r1] 1140 025c 66 11 mov #1, r1 1143 025e 5B 11 movu.B r1, r1 1146 0260 67 01 rtsd #4 1150 0262 62 14 add #1, r4 1152 0264 62 43 add #4, r3 1154 0266 61 44 cmp #4, r4 1155 0268 21 E2 bne .L61 1157 026a 66 01 mov #0, r1 1160 026c 5B 11 movu.B r1, r1 1163 026e 67 01 rtsd #4
こんにちは。NoMaYです。すみません。__builtin_rx_xchg()関数の引数を入れ替えたところ、セマフォのロックには使用出来ませんが、メモリオペランドを伴う命令列が生成されていましたので、GNURXのGCCの__builtin_rx_xchg()関数のソースのif節かelse節かは関係無いようですね。すみません。__builtin_rx_xchg()関数の引数を入れ替えてみた
// __builtin_rx_xchg((int *)&is_locked, (int *)&plock->lock); /* xchg(&is_locked, &plock->lock); */ __builtin_rx_xchg((int *)&plock->lock, (int *)&is_locked); /* xchg(&is_locked, &plock->lock); */
セマフォのロックには使用出来ないがメモリオペランドを伴う命令列が生成されていた
4 .global _R_BSP_SoftwareLock 11 0000 60 40 sub #4, r0 15 0002 EF 15 mov.L r1, r5 17 0004 EC 14 mov.L [r1], r4 19 0006 F8 06 01 mov.L #1, [r0] 21 0009 06 A0 10 04 xchg [r0].L, r4 23 000d 66 01 mov.L #0, r1 26 000f E3 54 mov.L r4, [r5] 28 0011 67 01 rtsd #4 31 .global _R_BSP_HardwareLock 33 _R_BSP_HardwareLock: 37 0013 60 40 sub #4, r0 41 0015 6C 21 shll #2, r1 43 0017 70 15 00 00 00 00 add #_g_bsp_Locks, r1, r5 48 001d EC 54 mov.L [r5], r4 50 001f F8 06 01 mov.L #1, [r0] 52 0022 06 A0 10 04 xchg [r0].L, r4 56 0026 66 01 mov.L #0, r1 60 0028 E3 54 mov.L r4, [r5] 64 002a 67 01 rtsd #4 67 .global _cmt_find_channel 69 _cmt_find_channel: 73 002c 60 40 sub #4, r0 76 002e FB 42 00 00 00 00 mov.L #_g_bsp_Locks+20, r4 78 0034 66 05 mov.L #0, r5 80 .balign 8,3,1 86 0036 EC 43 mov.L [r4], r3 88 0038 F8 06 01 mov.L #1, [r0] 90 003b 06 A0 10 03 xchg [r0].L, r3 95 003f 62 15 add #1, r5 101 0041 FD 22 43 mov.L r3, [r4+] 107 0044 61 45 cmp #4, r5 108 0046 21 F0 bne .L9 110 0048 66 01 mov.L #0, r1 112 004a 67 01 rtsd #4
こんにちは。NoMaYです。度々すみません。私が前々回と前回に試したケースは何れもGNURXのGCCの__builtin_rx_xchg()関数のソースのif節に該当していたようです。スタック上の変数のアドレスを&で取得した場合にもif文のREG_P(arg2)は真になるようです。よくよく考えてみれば、R0レジスタ相対になるのですから、そうなって然るべきものでした。今回、以下の4つの場合を試してみて、そのことを理解しました。(1) リエントラント性は脇において試しにis_locked変数をstatic宣言してみたもの
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 static int32_t is_locked = true;略 __builtin_rx_xchg((int *)&is_locked, (int *)&plock->lock);略
(2) 上記(1)で__builtin_rx_xchg()関数の引数を入れ替えたもの
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 static int32_t is_locked = true;略 __builtin_rx_xchg((int *)&plock->lock, (int *)&is_locked);略
(3) 上位関数から渡されたplock変数は脇において試しに&g_bsp_Locks[BSP_LOCK_CMT0 + 0]を書いたもの
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 int32_t is_locked = true;略 __builtin_rx_xchg((int *)&g_bsp_Locks[BSP_LOCK_CMT0 + 0], (int *)&is_locked);略
(4) 上記(3)で__builtin_rx_xchg()関数の引数を入れ替えたもの
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 int32_t is_locked = true;略 __builtin_rx_xchg((int *)&is_locked, (int *)&g_bsp_Locks[BSP_LOCK_CMT0 + 0]);略
結果は以下の通りでした。(1) リエントラント性は脇において試しにis_locked変数をstatic宣言してみたもの
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 static int32_t is_locked = true;略 __builtin_rx_xchg((int *)&is_locked, (int *)&plock->lock);略 4 .global _R_BSP_SoftwareLock 6 _R_BSP_SoftwareLock: 12 0000 FB 52 00 00 00 00 mov.L #_is_locked.1408, r5 13 0006 EC 54 mov.L [r5], r4 14 0008 06 A0 10 14 xchg [r1].L, r4 15 000c E3 54 mov.L r4, [r5] 18 000e EC 51 mov.L [r5], r1 21 0010 61 01 cmp #0, r1 22 0012 FC DB 10 sceq.L r1 23 0015 02 rts
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 static int32_t is_locked = true;略 __builtin_rx_xchg((int *)&plock->lock, (int *)&is_locked);略 4 .global _R_BSP_SoftwareLock 6 _R_BSP_SoftwareLock: 12 0000 EC 14 mov.L [r1], r4 13 0002 FB 52 00 00 00 00 mov.L #_is_locked.1408, r5 14 0008 EC 53 mov.L [r5], r3 15 000a E3 14 mov.L r4, [r1] 16 000c E3 53 mov.L r3, [r5] 19 000e EC 51 mov.L [r5], r1 22 0010 FC 43 34 xchg r3, r4 24 0013 61 01 cmp #0, r1 25 0015 FC DB 10 sceq.L r1 26 0018 02 rts
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 int32_t is_locked = true;略 __builtin_rx_xchg((int *)&g_bsp_Locks[BSP_LOCK_CMT0 + 0], (int *)&is_locked);略 6 _R_BSP_SoftwareLock: 11 0000 60 40 sub #4, r0 15 0002 FB 52 00 00 00 00 mov.L #_g_bsp_Locks+20, r5 16 0008 EC 54 mov.L [r5], r4 18 000a F8 06 01 mov.L #1, [r0] 20 000d 06 A0 10 04 xchg [r0].L, r4 22 0011 66 01 mov.L #0, r1 25 0013 E3 54 mov.L r4, [r5] 27 0015 67 01 rtsd #4
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 int32_t is_locked = true;略 __builtin_rx_xchg((int *)&is_locked, (int *)&g_bsp_Locks[BSP_LOCK_CMT0 + 0]);略 4 .global _R_BSP_SoftwareLock 6 _R_BSP_SoftwareLock: 11 0000 60 40 sub #4, r0 15 0002 F8 06 01 mov.L #1, [r0] 17 0005 EC 03 mov.L [r0], r3 18 0007 FB 52 00 00 00 00 mov.L #_g_bsp_Locks+20, r5 19 000d E3 03 mov.L r3, [r0] 20 000f EC 54 mov.L [r5], r4 22 0011 FC 43 43 xchg r4, r3 23 0014 E3 54 mov.L r4, [r5] 26 0016 EC 01 mov.L [r0], r1 28 0018 61 01 cmp #0, r1 29 001a FC DB 10 sceq.L r1 31 001d 67 01 rtsd #4
こんにちは。NoMaYです。幾つか前の私の投稿でGNURXのGCCの__builtin_rx_xchg()関数のソースについて「複雑難解な最適化処理との兼ね合いでどちらに転ぶか分からない不安があって悩ましい」と書きましたが、1つ例が思い浮かびました。今まで上位側で以下のようにしていたら期待したセマフォのロックに使用出来る命令列が生成されていた
/*static*/ bool cmt_find_channel (uint32_t * channel){ bool channel_found = false; uint32_t i; bool cmt_locked; /* Look for an available channel. */ for (i = 0; i < CMT_RX_NUM_CHANNELS; i++) {#if BSP_CFG_RTOS_USED == 0 // Non-OS#elif BSP_CFG_RTOS_USED == 1 // FreeRTOS if (i == BSP_CFG_RTOS_SYSTEM_TIMER) { /* Found CMT channel is being used for RTOS. */ continue; }#elif BSP_CFG_RTOS_USED == 2 // SEGGER embOS#elif BSP_CFG_RTOS_USED == 3 // Micrium MicroC/OS#elif BSP_CFG_RTOS_USED == 4 // Renesas RI600V4 & RI600PX#endif if (true == R_BSP_HardwareLock((mcu_lock_t)(BSP_LOCK_CMT0 + i))) { /* Channel found. */ *channel = i; channel_found = true; break; } } return channel_found;}
1104 .global _cmt_find_channel 1106 _cmt_find_channel: 1110 0240 60 40 sub #4, r0 1113 0242 FB 32 00 00 00 00 mov.L #_g_bsp_Locks+20, r3 1115 0248 66 04 mov.L #0, r4 1117 .balign 8,3,4 1123 024a F8 06 01 mov.L #1, [r0] 1125 024d EC 05 mov.L [r0], r5 1126 024f 06 A0 10 35 xchg [r3].L, r5 1127 0253 E3 05 mov.L r5, [r0] 1129 0255 EC 05 mov.L [r0], r5 1130 0257 61 05 cmp #0, r5 1131 0259 19 bne .L67 1137 025a E3 14 mov.L r4, [r1] 1140 025c 66 11 mov #1, r1 1143 025e 5B 11 movu.B r1, r1 1146 0260 67 01 rtsd #4 1150 0262 62 14 add #1, r4 1152 0264 62 43 add #4, r3 1154 0266 61 44 cmp #4, r4 1155 0268 21 E2 bne .L61 1157 026a 66 01 mov #0, r1 1160 026c 5B 11 movu.B r1, r1 1163 026e 67 01 rtsd #4
ところが以下のように書き換えたらそのような命令列が生成されなくなってしまった(ただの交換も機能しない)
/*static*/ bool cmt_find_channel (uint32_t * channel){ bool channel_found = false; uint32_t i; bool cmt_locked; /* Look for an available channel. */ for (i = 0; i < CMT_RX_NUM_CHANNELS; i++) {#if BSP_CFG_RTOS_USED == 0 // Non-OS#elif BSP_CFG_RTOS_USED == 1 // FreeRTOS if (i == BSP_CFG_RTOS_SYSTEM_TIMER) { /* Found CMT channel is being used for RTOS. */ continue; }#elif BSP_CFG_RTOS_USED == 2 // SEGGER embOS#elif BSP_CFG_RTOS_USED == 3 // Micrium MicroC/OS#elif BSP_CFG_RTOS_USED == 4 // Renesas RI600V4 & RI600PX#endif //if (true == R_BSP_HardwareLock((mcu_lock_t)(BSP_LOCK_CMT0 + i))) switch (i) { case 0: cmt_locked = R_BSP_HardwareLock((mcu_lock_t)BSP_LOCK_CMT0); break; case 1: cmt_locked = R_BSP_HardwareLock((mcu_lock_t)BSP_LOCK_CMT1); break; case 2: cmt_locked = R_BSP_HardwareLock((mcu_lock_t)BSP_LOCK_CMT2); break; case 3: cmt_locked = R_BSP_HardwareLock((mcu_lock_t)BSP_LOCK_CMT3); break; default: /* never */ cmt_locked = false; } if (true == cmt_locked) { /* Channel found. */ *channel = i; channel_found = true; break; } } return channel_found;}
74 .global _cmt_find_channel 76 _cmt_find_channel: 80 0034 6E 67 pushm r6-r7 82 0036 60 40 sub #4, r0 86 0038 66 05 mov.L #0, r5 91 003a FB 72 00 00 00 00 mov.L #_g_bsp_Locks+28, r7 98 0040 FB F2 00 00 00 00 mov.L #_g_bsp_Locks+32, r15 105 0046 FB E2 00 00 00 00 mov.L #_g_bsp_Locks+24, r14 112 004c FB 22 00 00 00 00 mov.L #_g_bsp_Locks+20, r2 114 .balign 8,3,1 115 .L13: 120 0052 61 25 cmp #2, r5 121 0054 20 6C beq .L7 123 0056 61 35 cmp #3, r5 124 0058 20 51 beq .L8 125 005a 61 15 cmp #1, r5 126 005c 20 2A beq .L9 131 005e F8 06 01 mov.L #1, [r0] 133 0061 EC 04 mov.L [r0], r4 134 0063 EC 23 mov.L [r2], r3 135 0065 E3 04 mov.L r4, [r0] 136 0067 FC 43 34 xchg r3, r4 138 006a EC 04 mov.L [r0], r4 139 006c 61 04 cmp #0, r4 140 006e FC DB 40 sceq.L r4 142 0071 E3 23 mov.L r3, [r2] 144 .balign 8,3,1 145 .L10: 150 0073 5B 44 movu.B r4, r4 151 0075 61 04 cmp #0, r4 152 0077 21 29 bne .L17 154 .balign 8,3,1 155 .L11: 157 0079 62 15 add #1, r5 159 007b 61 45 cmp #4, r5 160 007d 21 D5 bne .L13 162 007f CF 41 mov.B r4, r1 165 0081 5B 11 movu.B r1, r1 167 0083 3F 67 03 rtsd #12, r6-r7 169 .L9: 174 0086 E3 05 mov.L r5, [r0] 176 0088 EC 04 mov.L [r0], r4 177 008a EC E6 mov.L [r14], r6 178 008c E3 04 mov.L r4, [r0] 179 008e FC 43 64 xchg r6, r4 181 0091 EC 04 mov.L [r0], r4 182 0093 61 04 cmp #0, r4 183 0095 FC DB 40 sceq.L r4 185 0098 E3 E6 mov.L r6, [r14] 191 009a 5B 44 movu.B r4, r4 193 009c 61 04 cmp #0, r4 195 009e 20 DB beq .L11 197 .balign 8,3,1 198 .L17: 200 00a0 E3 15 mov.L r5, [r1] 203 00a2 66 11 mov #1, r1 206 00a4 5B 11 movu.B r1, r1 208 00a6 3F 67 03 rtsd #12, r6-r7 210 .L8: 215 00a9 F8 06 01 mov.L #1, [r0] 217 00ac EC 03 mov.L [r0], r3 218 00ae EC F6 mov.L [r15], r6 219 00b0 E3 03 mov.L r3, [r0] 220 00b2 E3 F6 mov.L r6, [r15] 222 00b4 EC 04 mov.L [r0], r4 223 00b6 61 04 cmp #0, r4 224 00b8 FC DB 40 sceq.L r4 227 00bb FC 43 63 xchg r6, r3 232 00be 2E B5 bra .L10 234 .L7: 239 00c0 F8 06 01 mov.L #1, [r0] 241 00c3 EC 04 mov.L [r0], r4 242 00c5 EC 76 mov.L [r7], r6 243 00c7 E3 04 mov.L r4, [r0] 244 00c9 FC 43 64 xchg r6, r4 246 00cc EC 04 mov.L [r0], r4 247 00ce 61 04 cmp #0, r4 248 00d0 FC DB 40 sceq.L r4 250 00d3 E3 76 mov.L r6, [r7] 256 00d5 2E 9E bra .L10