CPUは、アラインメントされていないアドレスへのアクセスをサポートしていません。実際にアクセスした場合、2回に分けてデータにアクセスしなければならないため、かえって遅くなります
コードやデータをメモリに読み書きする際には、ワードやハーフワードは、32bitのワードは4の倍数、16bitのハーフワードは2の倍数というように、アラインメントされたメモリアドレスに配置する必要があります。
STR,STRH,STM,LDM,LDRD,STRD,PUSH,POPの場合、アライメントのずれた下位ビットは無視され、メモリアクセスは強制的にアラインメントされた(切り捨てられた)メモリアドレスになります。
LDRD/STRDの場合、アドレスを8の倍数に揃える必要があるかどうかは明確に定義されていません。NDSでは4の倍数で問題ないようです。64bitデータバスを持つ他のCPUでは8の倍数のアラインメントが必要な場合もあります。
LDR,SWPでアラインメントされていないアドレスに対してメモリアクセスした場合、まず、addr AND (NOT 3)
と強制的にアラインメントされたアドレスからデータを読み取り、その後で、ROR (addr AND 3)*8
によってデータを回転させます。
この仕組みは、LDRBとLDRHで不要なbitをクリアするために、内部的に利用されています。
SWPは、LDRとSTRを組み合わせたような動作をします。つまり、読み出しは結果を回転させますが、書き込みは書き込む値を回転させません。
ARM9(ARMv5) on NDS9 の場合、
LDRH Rd,[odd] --> LDRH Rd,[odd-1]
LDRSH Rd,[odd] --> LDRSH Rd,[odd-1]
と強制的にアラインメントされます。
ARM7(ARMv4) on NDS7/GBA の場合、
LDRH Rd,[odd] --> LDRH Rd,[odd-1] ROR 8 ; read to bit0-7 and bit24-31
LDRSH Rd,[odd] --> LDRSB Rd,[odd] ; sign-expand BYTE value
ARMコードの場合、ターゲットアドレスの下位ビットは通常0でなければならず、そうでない場合は下位2ビットをクリアすることでR15を強制的にアラインメントします。
THUMBコードの場合、ターゲットアドレスの下位1ビットがセットされ、そのビットがTHUMBビットとして解釈され(または解釈されない)、下位1ビットをクリアすることでR15が強制的にアラインされます。
つまり、R15は常に強制的にアラインメントされるので、アラインメントされていない分岐命令は、R15または[R15+disp]
をオペランドとして使用する後続のオペコードに影響を与えません。