新版FM音源プログラム (15)
今回は各種のチップ/コンパイラの組み合わせのオブジェクトに対する逆アセンブル・リストを掲載します。
もとの C ソース・ファイルでの記述を少し変えると、コンパイル後のオブジェクトはかなり大きく変化するので、あまり細部に渡る追及はしないでおきます。
μVision V5.21a (armcc コンパイラ) でコンパイルした calc_slot() 関数を逆アセンブルしたものを下に示します。
Cortex-M4 コアの STM32F446、STM32F407、STM32F303 に共通です。
# uVision V5.21a (armcc v5.06 update 3) # options: -O3 -cpu Cortex-M4.fp 08000ed4 <calc_slot>: 8000ed4: e92d 4030 stmdb sp!, {r4, r5, lr} 8000ed8: e9d0 2300 ldrd r2, r3, [r0] 8000edc: 441a add r2, r3 8000ede: 6042 str r2, [r0, #4] 8000ee0: 6883 ldr r3, [r0, #8] 8000ee2: 68c4 ldr r4, [r0, #12] 8000ee4: 441a add r2, r3 8000ee6: 8a03 ldrh r3, [r0, #16] 8000ee8: 1e89 subs r1, r1, #2 8000eea: ea03 2312 and.w r3, r3, r2, lsr #8 8000eee: 5ee3 ldrsh r3, [r4, r3] 8000ef0: 6942 ldr r2, [r0, #20] 8000ef2: 435a muls r2, r3 8000ef4: 13d3 asrs r3, r2, #15 8000ef6: f9b0 2012 ldrsh.w r2, [r0, #18] 8000efa: 8243 strh r3, [r0, #18] 8000efc: 8b04 ldrh r4, [r0, #24] 8000efe: 441a add r2, r3 8000f00: 4354 muls r4, r2 8000f02: 6084 str r4, [r0, #8] 8000f04: 8e84 ldrh r4, [r0, #52] ; 0x34 8000f06: f100 021c add.w r2, r0, #28 8000f0a: 435c muls r4, r3 8000f0c: e9d2 3500 ldrd r3, r5, [r2] 8000f10: 442b add r3, r5 8000f12: 6203 str r3, [r0, #32] 8000f14: 4423 add r3, r4 8000f16: 8d84 ldrh r4, [r0, #44] ; 0x2c 8000f18: 6a85 ldr r5, [r0, #40] ; 0x28 8000f1a: ea04 2413 and.w r4, r4, r3, lsr #8 8000f1e: 6b03 ldr r3, [r0, #48] ; 0x30 8000f20: 5f2c ldrsh r4, [r5, r4] 8000f22: 4363 muls r3, r4 8000f24: 13db asrs r3, r3, #15 8000f26: 85c3 strh r3, [r0, #46] ; 0x2e 8000f28: 3038 adds r0, #56 ; 0x38 8000f2a: 2900 cmp r1, #0 8000f2c: dcd4 bgt.n 8000ed8 <calc_slot+0x4> 8000f2e: bd30 pop {r4, r5, pc}
gcc ツールチェインの「objdump」を使っているため、armcc の .o オブジェクト・ファイルには対応しておらず、リンクずみの .axf ファイルを入力としています。
アーキテクチャは 32/16 ビット命令の thumb2 インストラクション・セットを持つ ARMv7-M ですが、多くが 16 ビット thumb 命令へコンパイルされていて、ARMv6-M にはない 32 ビット thumb2 命令は少数となっています。
Atollic TrueSTUDIO for STM32 v9.0.0 (gcc 6.3.1) によるコンパイル結果を逆アセンブルしたものを下に示します。
# Atollic TrueSTUDIO for STM32 v9.0.0 (gcc 6.3.1) # options: -Os -mcpu=cortex-m4 00000000 <calc_slot>: 0: b530 push {r4, r5, lr} 2: 3038 adds r0, #56 ; 0x38 4: f850 2c34 ldr.w r2, [r0, #-52] 8: f850 3c38 ldr.w r3, [r0, #-56] c: f850 5c18 ldr.w r5, [r0, #-24] 10: 4413 add r3, r2 12: f850 2c30 ldr.w r2, [r0, #-48] 16: f840 3c34 str.w r3, [r0, #-52] 1a: 4413 add r3, r2 1c: f830 2c28 ldrh.w r2, [r0, #-40] 20: ea02 2313 and.w r3, r2, r3, lsr #8 24: f850 2c2c ldr.w r2, [r0, #-44] 28: 5ed2 ldrsh r2, [r2, r3] 2a: f850 3c24 ldr.w r3, [r0, #-36] 2e: 4353 muls r3, r2 30: f930 2c26 ldrsh.w r2, [r0, #-38] 34: 13db asrs r3, r3, #15 36: 189c adds r4, r3, r2 38: f830 2c20 ldrh.w r2, [r0, #-32] 3c: f820 3c26 strh.w r3, [r0, #-38] 40: 4362 muls r2, r4 42: f840 2c30 str.w r2, [r0, #-48] 46: f850 2c1c ldr.w r2, [r0, #-28] 4a: f830 4c04 ldrh.w r4, [r0, #-4] 4e: 442a add r2, r5 50: f840 2c18 str.w r2, [r0, #-24] 54: fb03 2204 mla r2, r3, r4, r2 58: f830 3c0c ldrh.w r3, [r0, #-12] 5c: ea03 2312 and.w r3, r3, r2, lsr #8 60: f850 2c10 ldr.w r2, [r0, #-16] 64: 5ed2 ldrsh r2, [r2, r3] 66: f850 3c08 ldr.w r3, [r0, #-8] 6a: 3902 subs r1, #2 6c: 4353 muls r3, r2 6e: 13db asrs r3, r3, #15 70: 2900 cmp r1, #0 72: f820 3c0a strh.w r3, [r0, #-10] 76: f100 0038 add.w r0, r0, #56 ; 0x38 7a: dcc3 bgt.n 4 <calc_slot+0x4> 7c: bd30 pop {r4, r5, pc}
32 ビット thumb2 命令が多用されていますが、そのほとんどがマイナス・オフセットを持つ ldr/ldrh/ldrsh/str/strh 命令で、シフト付きオペランドなどの 32 ビット thumb2 固有の命令は少数となっています。
リンク前のオブジェクト・ファイル「calc_slot.o」を逆アセンブルしています。
μVision V5.21a (armcc v5.06 update 3) で LPC1114 (Cortex-M0, ARMv6-M) 用にコンパイルした結果の逆アセンブル・リストを下に示します。
# uVision v5.21a (armcc v5.06 update 3) # options: -O3 -cpu Cortex-M0 0000049c <calc_slot>: 49c: b530 push {r4, r5, lr} 49e: c80c ldmia r0!, {r2, r3} 4a0: 3808 subs r0, #8 4a2: 189a adds r2, r3, r2 4a4: 6042 str r2, [r0, #4] 4a6: 6883 ldr r3, [r0, #8] 4a8: 68c4 ldr r4, [r0, #12] 4aa: 189a adds r2, r3, r2 4ac: 8a03 ldrh r3, [r0, #16] 4ae: 0a12 lsrs r2, r2, #8 4b0: 4013 ands r3, r2 4b2: 5ee3 ldrsh r3, [r4, r3] 4b4: 6942 ldr r2, [r0, #20] 4b6: 1e89 subs r1, r1, #2 4b8: 435a muls r2, r3 4ba: 13d3 asrs r3, r2, #15 4bc: 2212 movs r2, #18 4be: 5e82 ldrsh r2, [r0, r2] 4c0: 8243 strh r3, [r0, #18] 4c2: 8b04 ldrh r4, [r0, #24] 4c4: 18d2 adds r2, r2, r3 4c6: 4354 muls r4, r2 4c8: 6084 str r4, [r0, #8] 4ca: 8e84 ldrh r4, [r0, #52] ; 0x34 4cc: 4602 mov r2, r0 4ce: 321c adds r2, #28 4d0: 435c muls r4, r3 4d2: ca28 ldmia r2!, {r3, r5} 4d4: 3a08 subs r2, #8 4d6: 18eb adds r3, r5, r3 4d8: 6053 str r3, [r2, #4] 4da: 191b adds r3, r3, r4 4dc: 8a14 ldrh r4, [r2, #16] 4de: 0a1b lsrs r3, r3, #8 4e0: 401c ands r4, r3 4e2: 68d5 ldr r5, [r2, #12] 4e4: 6953 ldr r3, [r2, #20] 4e6: 5f2c ldrsh r4, [r5, r4] 4e8: 3038 adds r0, #56 ; 0x38 4ea: 4363 muls r3, r4 4ec: 13db asrs r3, r3, #15 4ee: 8253 strh r3, [r2, #18] 4f0: 2900 cmp r1, #0 4f2: dcd4 bgt.n 49e <calc_slot+0x2> 4f4: bd30 pop {r4, r5, pc}
TrueSTUDIO for STM32 v9.0.0 は Atollic が STMicro に買収されてからリリースされたバージョンで、制限なし版が無償で提供されていますが、当然 STM32 シリーズのサポートのみとなり、他社のチップには対応していません。
そんなわけで、LPC1114 版は μVision によるコンパイル結果のみを示しています。
細かいことは言わないと言っておきながら、細かい部分に触れますが、冒頭部分、
49e: c80c ldmia r0!, {r2, r3} 4a0: 3808 subs r0, #8
は、連続されて格納されている ph_inc、ph_acc を r2、r3 にロードするコードですが、16 ビット thumb 命令の範囲では、LDM (LoaD Multiple) 命令は「IA」(Increment After) 付き、および「!」(ライトバック・サフィックス) 付きに限られ、命令の実行後に op_prop[] ポインタの r0 が 8 進んでしまうのを、次の subs r0,#8 で戻しています。
もとの C ソースで、サイン波テーブルのアクセスに、
phh >>= (PH_ACC_FRAC_BITS-1); out = *(int16_t *)((uint8_t *)o_p->stab_p + (o_p->ind_mask & phh));
のように、元々 (int16_t *) である o_p->stab_p を (uint8_t *) でキャストし、バイト・アドレッシングでポインタのオフセットを計算してから、それを再び (int16_t *) にキャストし直すという、一見変な処理をしています。
これは、Cortex-M0 (ARMv6-M) 用にコンパイルした場合に余計なシフト命令が挿入されないようにするためです。
Cortex-M3/M4 (ARMv7-M) では、thumb2 命令の中に「シフト付きオペランド」を持つ命令があるので、r4 にサイン波テーブルアドレス、r3 に「ハーフワード・インデクス」としてのオフセットが格納されている場合、
ldrsh r2, [r4, r3, lsl #1]
のように、1 命令で「ハーフワード・インデクス」から「バイト・オフセット」に変換しながらアクセスすることができます。
それに対して「シフト付きオペランド」を持たない Cortex-M0 (ARMv6-M) では、
lsls r3, r3, #1 ldrsh r2, [r4, r3]
のようにシフト命令が強制的に挿入されて「ハーフワード・インデクス」から「バイト・オフセット」に変換されます。
フェーズ・アキュムレータの値からサイン波テーブルのオフセットを求めるのに、シフトおよびマスクが欠かせないので、それらの処理をあらかじめバイト・オフセットの領域で計算しておけば、「余分」なシフト命令が不要になります。