CQ-FRK-FM3 基板用FM音源プログラム -- TGFM3 (8)
gcc の「-mstructure-size-boudary=」オプションの指定による違いについて、ハードウェア・ウォッチドッグ・タイマにアクセスする部分を具体例として示します。
まず、「mb9b610t.h」中のハードウェア・ウォッチドッグ・タイマの union / struct 定義部分を下に示します。
/* HWWDT_MODULE register bit fields */ typedef struct stc_hwwdt_wdg_ctl_field { __IO uint8_t INTEN : 1; __IO uint8_t RESEN : 1; } stc_hwwdt_wdg_ctl_field_t; typedef struct stc_hwwdt_wdg_ris_field { __IO uint8_t RIS : 1; } stc_hwwdt_wdg_ris_field_t; /* Hardware watchdog registers */ typedef struct { __IO uint32_t WDG_LDR; __IO uint32_t WDG_VLR; union { __IO uint8_t WDG_CTL; stc_hwwdt_wdg_ctl_field_t WDG_CTL_f; }; uint8_t RESERVED0[3]; __IO uint8_t WDG_ICL; uint8_t RESERVED1[3]; union { __IO uint8_t WDG_RIS; stc_hwwdt_wdg_ris_field_t WDG_RIS_f; }; uint8_t RESERVED2[3055]; __IO uint32_t WDG_LCK; }FM3_HWWDT_TypeDef;
この定義が正しくコンパイルされた場合の、アドレス・オフセットの割り付けは下の図のようになります。
この状態で、「system_mb9bf61xt.c」 ファイル中の SystemInit() 関数の始めの部分でハードウェア・ウォッチドッグ・タイマを停止している記述、
FM3_HWWDT->WDG_LCK = 0x1ACCE551; /* HW Watchdog Unlock */ FM3_HWWDT->WDG_LCK = 0xE5331AAE; FM3_HWWDT->WDG_CTL = 0; /* HW Watchdog stop */
は、次のようにコンパイルされます。
最適化オプションは「-Os」、つまりサイズを優先する指定にしています。
00000240 <SystemInit>: 240: 4b28 ldr r3, [pc, #160] ; (2e4) 242: 4a29 ldr r2, [pc, #164] ; (2e8) 244: 2101 movs r1, #1 246: f8c3 2c00 str.w r2, [r3, #3072] ; 0xc00 24a: 4a28 ldr r2, [pc, #160] ; (2ec) 24c: f8c3 2c00 str.w r2, [r3, #3072] ; 0xc00 250: 2200 movs r2, #0 252: 721a strb r2, [r3, #8] . . . < 中略 > . . .. 2e4: 40011000 .word 0x40011000 2e8: 1acce551 .word 0x1acce551 2ec: e5331aae .word 0xe5331aae
アドレス 0x246、0x24C の「str.w」命令でロック・レジスタ (WDG_LCK) にロック解除の固定パターンを書き込んでおり、そのオフセットは正しく 0xC00 になっています。
gcc 自体のデフォルトでは、「-mstructure-size-boundary=32」(長いので以降は 「-ms-s-b=」と略記)ですが、ARM 用 gcc としては -ms-s-b=8 とするのが通例のようです。
したがって、普通は特に -ms-s-b= のオプションを指定しなくても正しくコンパイルされます。
しかし、なぜか PizzaFactry8 (CQ 版) 付属の gcc ツールチェインでは、-ms-s-b=8 の設定になっていないようで、-ms-s-b=8 オプションを明示しないと正しくコンパイルされません。
一般の ARM 用 gcc で -ms-s-b=32 オプションを指定した場合、および、PizzaFactory8 (CQ 版) のデフォルト状態では、下の図のように、アドレス・オフセットが正しくなりません。
図の緑色のドットの部分は、-ms-s-b=32 のオプション指定により、ビット・フィールド換算で 32 ビットに満たない数のビットをパッキングする際に付加されるパディング部分を示しています。
この「余計」な部分は合計で 8 バイトあり、WDG_LCK へのオフセットが正しくは 0x0C00 なのに、0x0C08 となっています。
この状態でコンパイルした結果を下に示します。
00000240 <SystemInit>: 240: 4b2a ldr r3, [pc, #168] ; (2ec) 242: 4a2b ldr r2, [pc, #172] ; (2f0) 244: 2101 movs r1, #1 246: f8c3 2c08 str.w r2, [r3, #3080] ; 0xc08 24a: 4a2a ldr r2, [pc, #168] ; (2f4) 24c: f8c3 2c08 str.w r2, [r3, #3080] ; 0xc08 250: 2200 movs r2, #0 252: 721a strb r2, [r3, #8] . . . < 中略 > . . .. 2ec: 40011000 .word 0x40011000 2f0: 1acce551 .word 0x1acce551 2f4: e5331aae .word 0xe5331aae
アドレス 0x246、0x24C の「str.w」命令のオフセットは 0xC08 であり、正しくない値になっています。
コントロール・レジスタ (WDG_CTL) のオフセットは 0x08 で正しいのですが、ロック・レジスタに正しくアクセスできていないのでロックが外れず、ハードウェア・ウォッチドッグは解除されないままとなります。
1 バイト単位でのパッキングを指定する方法には、-mstructure-size-boundary= オプションのほかに、-fpack-struct オプションを使う方法もあります。
しかし、-fpack-struct オプションには、著しい「副作用」があります。
「-fpack-struct」オプションを付けてコンパイルした結果を示します。
00000240 <SystemInit>: 240: b530 push {r4, r5, lr} 242: 4b4e ldr r3, [pc, #312] ; (37c) 244: 2151 movs r1, #81 ; 0x51 246: f893 2c00 ldrb.w r2, [r3, #3072] ; 0xc00 24a: f883 1c00 strb.w r1, [r3, #3072] ; 0xc00 24e: f893 1c01 ldrb.w r1, [r3, #3073] ; 0xc01 252: f06f 011a mvn.w r1, #26 256: f883 1c01 strb.w r1, [r3, #3073] ; 0xc01 25a: f893 0c02 ldrb.w r0, [r3, #3074] ; 0xc02 25e: f06f 0033 mvn.w r0, #51 ; 0x33 262: f883 0c02 strb.w r0, [r3, #3074] ; 0xc02 266: f893 0c03 ldrb.w r0, [r3, #3075] ; 0xc03 26a: 201a movs r0, #26 26c: f883 0c03 strb.w r0, [r3, #3075] ; 0xc03 270: f893 4c00 ldrb.w r4, [r3, #3072] ; 0xc00 274: f06f 0451 mvn.w r4, #81 ; 0x51 278: f883 4c00 strb.w r4, [r3, #3072] ; 0xc00 27c: f893 4c01 ldrb.w r4, [r3, #3073] ; 0xc01 280: f883 0c01 strb.w r0, [r3, #3073] ; 0xc01 284: f893 0c02 ldrb.w r0, [r3, #3074] ; 0xc02 288: 2033 movs r0, #51 ; 0x33 28a: f883 0c02 strb.w r0, [r3, #3074] ; 0xc02 28e: 2200 movs r2, #0 290: f893 0c03 ldrb.w r0, [r3, #3075] ; 0xc03 294: f883 1c03 strb.w r1, [r3, #3075] ; 0xc03 298: 721a strb r2, [r3, #8] . . . < 中略 > . . .. 37c: 40011000 .word 0x40011000
異様に長いですが、何をやっているのかと言えば、32 ビット・レジスタである WDG_LCK を 8 ビット単位でアクセスするコードになっています。
レジスタに対するオフセットは 0xC00 〜 0xC03 で、正しい値であり、メモリ上の変数に対するアクセスであれば「遅い」だけで正常な動作となるのですが、WDG_LCK レジスタは 32 ビット幅でアクセスする必要があり、8 ビット幅のアクセスでは正しく機能しません。