ARM アセンブラ operand2
Cortex-A Series プログラマーズガイド (DEN0013C) を精読せずいい加減に読んでると、最後のオペランド (つまり operand2) はバリエーションがたくさんあって手強いという印象を持ちました。
たとえば、以下のようなオペランドが例として記載されていました。
add R0, R1, R2, LSL #4
stmfd sp!, {fp, ip, lr, pc}
ldmfd sp, {fp, sp, pc}
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
最初の例にある R2, LSL #4 は
6.2.1 Operand 2 and the barrel shifter
を落ち着いて読めばちゃんと解説されていました。
次の2つ、stmfd と ldmfd は Load/Store Multiple なるもので、 { } でくくられたリストはロードまたはストアの対象となるレジスタで複数並べられます。ちなみに、ロード・ストアされる順番は、並び順ではなくて、レジスタ番号に従った順序だそうです。
最後の例は MSR (Move Status Register or Coprocessor Register from General Purpose Register) の命令仕様と CPSR (Current Program Status Register)のビット定義をじっくり見比べるとやりたいことは理解できます。ここで Mode_FIQ、I_BIT、F_BIT は EQU ディレクティブ (C言語の #define マクロ?) で置き換えられた定数と思われますが、Linux のソースコード(linux-xlnx.git) を探しても見当たりませんでした。あと、:OR: は ARMアセンブラの場合で、GNUの場合は | になります。以上を確認するため、下記のコードをコンパイル・リンクできることを確認しました。実行しても何も起りませんが
int main(int argc, char *argv)
{
asm volatile(" \
.equ Mode_FIQ, 0x11 ; \
.equ I_BIT , 0x80 ; \
.equ F_BIT , 0x40 ; \
MSR CPSR_c, #Mode_FIQ | I_BIT | F_BIT ; \
");
return 0;
}
前後しますが、最初の例の LSL (left shift) を含むサンプルも実行してみました。
#include <stdio.h>
int main(int argc, char *argv)
{
register unsigned int v4;
register unsigned int v5;
register unsigned int v6;
asm volatile(" \
MOVW %0, #0xdead; \
MOVW %1, #0xbeaf; \
ADD %2, %1, %0, LSL #16; \
" : "=r"(v4), "=r"(v5), "=r"(v6));
printf("%x\t%x\t%x\n", v4, v5, v6);
return 0;
}
これは下記のようのに結果が確認できます
root@zynq:~# ./a.out
dead beaf deadbeaf
たとえば、以下のようなオペランドが例として記載されていました。
add R0, R1, R2, LSL #4
stmfd sp!, {fp, ip, lr, pc}
ldmfd sp, {fp, sp, pc}
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
最初の例にある R2, LSL #4 は
6.2.1 Operand 2 and the barrel shifter
を落ち着いて読めばちゃんと解説されていました。
次の2つ、stmfd と ldmfd は Load/Store Multiple なるもので、 { } でくくられたリストはロードまたはストアの対象となるレジスタで複数並べられます。ちなみに、ロード・ストアされる順番は、並び順ではなくて、レジスタ番号に従った順序だそうです。
最後の例は MSR (Move Status Register or Coprocessor Register from General Purpose Register) の命令仕様と CPSR (Current Program Status Register)のビット定義をじっくり見比べるとやりたいことは理解できます。ここで Mode_FIQ、I_BIT、F_BIT は EQU ディレクティブ (C言語の #define マクロ?) で置き換えられた定数と思われますが、Linux のソースコード(linux-xlnx.git) を探しても見当たりませんでした。あと、:OR: は ARMアセンブラの場合で、GNUの場合は | になります。以上を確認するため、下記のコードをコンパイル・リンクできることを確認しました。実行しても何も起りませんが
int main(int argc, char *argv)
{
asm volatile(" \
.equ Mode_FIQ, 0x11 ; \
.equ I_BIT , 0x80 ; \
.equ F_BIT , 0x40 ; \
MSR CPSR_c, #Mode_FIQ | I_BIT | F_BIT ; \
");
return 0;
}
前後しますが、最初の例の LSL (left shift) を含むサンプルも実行してみました。
#include <stdio.h>
int main(int argc, char *argv)
{
register unsigned int v4;
register unsigned int v5;
register unsigned int v6;
asm volatile(" \
MOVW %0, #0xdead; \
MOVW %1, #0xbeaf; \
ADD %2, %1, %0, LSL #16; \
" : "=r"(v4), "=r"(v5), "=r"(v6));
printf("%x\t%x\t%x\n", v4, v5, v6);
return 0;
}
これは下記のようのに結果が確認できます
root@zynq:~# ./a.out
dead beaf deadbeaf