2. ARMのレジスタ
ARM CPUの命令セットを見ていく前に、ARMのレジスタを見ておきましょう。Linuxで プログラミングする場合に必要なユーザモードから見えるレジスタに限定します。
汎用レジスタ
ARMプロセッサは r0 から r15 の16本の32ビットレジスタを持っています。 そのうち r15 はプログラムカウンタで実行中のメモリアドレスを保持しています。 r14 はリンクレジスタで BL 命令(サブルーチンコール)で分岐した場合の戻りアドレス を保持します。リンクレジスタは1つの戻りアドレスしか保持できないため、 スタック (普通は r13 が示す領域) に保存する場合が多くなります。 その他の14本のレジスタは汎用レジスタとして同じ機能を持っています。
- レジスタ
31 | 30 | 29 | 28 | .. bit .. | 3 | 2 | 1 | 0 |
r0 | ||||||||
r1 | ||||||||
: | ||||||||
r13 (SP) | ||||||||
r14 (LR) | ||||||||
r15 (PC) |
GNU as では、r0 - r15 という番号によるレジスタの指定方法以外に、 別名でもレジスタを指定できます。 r15 は pc、r14 は lr、r13 は sp と表記するほうが分かりやすくなります。 標準的なレジスタの使い方から決められた別名が利用できるようになっています。 a1-a4,ip は引数や返り値、テンポラリ変数のように破壊可能なレジスタ。 v1-v8 は下位のサブルーチンで破壊しないようにするのがマナーのようです。 アセンブラでカーネルのシステムコールを呼び出すプログラムを開発する場合は、 r0 から r13 までのレジスタは自由に使用できるため、とくに気にする必要は ありませんが、汎用レジスタの数が多いので守っておくとレジスタの使い方に 迷いにくくなると思います。
次の表は GNU as で指定可能なレジスタ名と別名です。
レジスタ | 別名 | 説明 | |
---|---|---|---|
r0 | a1 |   | 汎用レジスタ |
r1 | a2 |   | 汎用レジスタ |
r2 | a3 |   | 汎用レジスタ |
r3 | a4 |   | 汎用レジスタ |
r4 | v1 |   | 汎用レジスタ |
r5 | v2 |   | 汎用レジスタ |
r6 | v3 |   | 汎用レジスタ |
r7 | v4 | wr | 汎用レジスタ |
r8 | v5 |   | 汎用レジスタ |
r9 | v6 | sb | 汎用レジスタ |
r10 | v7 | sl | 汎用レジスタ |
r11 | v8 | fp | 汎用レジスタ |
r12 | ip |   | 汎用レジスタ |
r13 | sp |   | 汎用レジスタ、スタックポインタ |
r14 | lr |   | リンクレジスタ |
r15 | pc |   | プログラムカウンタ |
ステータスレジスタと条件指定実行
ARMステートにおいては,すべての命令に4ビットの条件フィールドが付いて、 ステータスレジスタ(CPSR)の C,N,Z,Vフラグの状態にしたがって、命令が 実行されるかどうかを指定することができます。
- ステータスレジスタ
31 | 30 | 29 | 28 | 27 | .. bit .. | 1 | 0 |
N | Z | C | V | Q |   |   |   |
各フラグの意味を示します。
bit | フラグ | 意味 | 備考 |
---|---|---|---|
31 | N | ネガティブ | 2の補数表現で負なら1 |
30 | Z | ゼロ | ゼロなら1 |
29 | C | キャリー/ボロー | 無符号加減算の桁あふれの時1 |
28 | V | オーバーフロー | 符号付加減算の桁あふれの時1 |
27 | Q | オーバーフロー | オーバーフロー、飽和(DSP)の時1 |
ARMステートのすべての命令は、アルファベット2文字から成る接尾辞 (サフィックス) を 命令 (ニーモニック) に続けることで、15種類の実行条件を指定することができます。 例えば分岐命令(B)で "等しい時に分岐" の場合は "BEQ"、 "等しくない時に分岐" なら "BNE" になります。 この場合は Zフラグの状態で分岐を実行するかどうかが決まります。 他のCPUでも分岐命令は同様な動作をしますが、ARMではどの命令でも条件を指定できます。 サフィックスを省略すると,AL(ALways)が指定されたことになり、 命令はステータスレジスタの内容に関係なく実行されます。
条件 (<cd>) | 意味 | フラグ条件 | |
---|---|---|---|
AL | 無条件に実行 | 無条件 | - |
EQ | 等しい | Zセット | Z=1 |
NE | 等しくない | Zクリア | Z=0 |
MI | 負 | Nセット | N=1 |
PL | 正かゼロ | Nクリア | N=0 |
VS | オーバフロー | Vセット | V=1 |
VC | オーバフローでない | Vクリア | V=0 |
CS/HS | ≧ 大きいか等しい (符号無し) | Cセット | C=1 |
CC/LO | < 小さい (符号無し) | Cクリア | C=0 |
HI | > 大きい (符号無し) | CセットかつZクリア | C=1 AND Z=0 |
LS | ≦ 小さいか等しい (符号無し) | CクリアまたはZセット | C=0 OR Z=1 |
GE | ≧ 大きいか等しい (符号付き) | NとVが同じ | (N=1 AND V=1) OR (N=0 AND V=0) |
LT | < 小さい (符号付き) | NとVが異なる | (N=1 AND V=0) OR (N=0 AND V=1) |
GT | > 大きい (符号付き) | GEの条件かつZクリア | Z=0 AND N=V |
LE | ≦ 小さいか等しい (符号付き) | LTの条件かつZクリア | Z=1 AND N!=V |
減算命令 (SUB) を例にすると、SUB だけの場合は無条件実行(AL)を示し、
SUBNE とするとZフラグが1でない(非ゼロ)場合に減算を実行します。Zフラグが
0の場合は、減算自体を実行しません。さらに演算命令の場合は条件指定の
サフィックスの後ろに、命令の実行結果によってステータスフラグを更新する
指定である S を付加することができます。したがって減算命令 (SUB) だけで
次のように30種類の命令の表記法があります。
はじめの SUBAL と SUBALS はそれぞれ SUB と SUBS のように AL を省略できます。
SUBAL | SUBALS |
SUBEQ | SUBEQS |
SUBNE | SUBNES |
SUBCS | SUBCSS |
SUBCC | SUBCCS |
SUBHI | SUBHIS |
SUBLS | SUBLSS |
SUBGE | SUBGES |
SUBLT | SUBLTS |
SUBGT | SUBGTS |
SUBLE | SUBLES |
SUBMI | SUBMIS |
SUBPL | SUBPLS |
SUBVS | SUBVSS |
SUBVC | SUBVCS |
実際のプログラムソース中に現れた場合、命令の表記 (ニーモニック) が長くなって
知らない命令のように感じる場合もありますが、上の表の仕組みを思い出してください。
SUB命令の実際の例を1つ示しておきます。
@ Zフラグが0 (0でない) ならば、 r1 = r2 - r3 を計算してフラグを更新 SUBNES r1, r2, r3