アライメントのなく頃に 目明し編

AS「君の速さに対する情熱は、保守性を凌駕した。さあ、解き放ってごらん。その新しい技術を!」

通常、.alignというPseudo命令はバイト境界を調整するために使います。例えば、32ビットのデータを4の倍数のアドレスに置くときです。これは、32ビットのデータにCPUがアクセスするときに、データの置かれているアドレスが4の倍数でないとバスエラーを出すCPUが多いからです。

しかし、AVRがメモリにアクセスするときは1byte単位なので、このような問題は発生しません。では前回書いた8バイト境界にアライメントするというのはどのような場面だったのでしょうか。

AVRのアセンブラでRAM中のテーブルにアクセスするときは次のように書きます。

.section .data
FOO: .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07

.section .text
.align 1
.func FUNC
FUNC:
何か適当な処理
R1にテーブルのインデックスが入っているとする (0<= R1 <=7)
CLR R0
LDI ZH, hi8(FOO)
LDI ZL, lo8(FOO)
ADD ZL, R1
ADC ZH, R0 (※)
LD R2, Z

上記のコードはC言語風に書くと
uint8_t FOO[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
R2=FOO[R1];
となります。

さて、ここで(※)の行について考えます。この行でZHがインクリメントされるのは1つ前の行でオーバーフローが発生したときです。R1が(0<= R1 <= 7)を満たしているのでlo8(FOO) < 249 の時には(※)の行は無くてもかまいません。

しかし、アドレスはリンカに決めさせたいので即値を書くわけにはいきません。そこで、FOOの先頭アドレスを8バイト境界にアライメントするとlo8(FOO) <= 248であることが保障されるので(※)の行を削ることができます。

たった1命令ですら節約したい、時間的にクリティカルな処理の中では有効な手段です。もっとも通常はこんなテクニックを使う前に大局的な最適化をしたほうが効果的です。最後の最後にチューニングをするときの手段だと思ってください。

by Shiozaki

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です