命令セット

命令セットの概要

なぜ命令セットの理解が必要か?

今回は、初期化や割り込みハンドラを実装する場合に必要な命令セットの基本知識を学びます。デバッグを行う時やチューニングを行う場合に、命令セットの知識があることで、開発を円滑に進めることができます。命令の詳細については、「ARMおよびThumb-2 命令セットクイックリファレンスカード」を参照ください。

Cortex-Aがサポートする命令セット

ARMプロセッサは、ARM命令(32ビット)セットとThumb命令(16ビット)セットの2つの命令セットを採用していました。Cortex-Aシリーズは、ARM命令セット(A32(ARM))とThumb命令セットの新版であるThumb-2命令セットを採用しています。

ARM命令セット

ARM命令セットは、32ビット固定長命令セットで、ARMv4T、ARMv5TEJおよびARMv6アーキテクチャで使用されています。性能が重視される場合や互換性のために、Cortex-AおよびCortex-Rプロファイルでもサポートされています。

Thumb-2命令セット

16ビット固定長命令セットとして導入され、Thumb-2技術の導入で、16ビットおよび32ビット命令長の混在命令セットです。ARM命令セットのパフォーマンスと、Thumb命令セットのコード密度の特徴をあわせ持つ、Cortexシリーズの主力命令セットです。

命令セットのプロセス

アセンブリ命令の基本形式

アセンブラ記述は、C言語の演算と同様に、後ろから前へ演算を行います。ADD(加算命令)を例に、アセンブリ命令の基本形式を示します。

図1

オペランド数は、命令により異なりますので、「ARMおよびThumb-2 命令セットクイックリファレンスカード」で確認してください。

データ処理命令

データ処理命令とは、レジスタ間で転送、演算を行う命令の総称で、命令セットを学ぶ上での基本となります。すべてのARMプロセッサはロード/ストア・アーキテクチャを採用しており、演算処理はレジスタで行います。

  • ①レジスタのデータを転送します。
  • ②イミディエイト値をレジスタに代入します
  • ③イミディエイト値とレジスタ間で加算します。
  • ④イミディエイト値とレジスタ間で減算します。
  • ⑤レジスタ間を加算します。
  • ⑥レジスタ間を減算します。
  • ⑦イミディエイト値とレジスタ間でAND論理演算します。
  • ⑧イミディエイト値とレジスタ間でOR論理演算します。
  • ⑨レジスタ間でAND論理演算します。
  • ⑩レジスタ間でOR論理演算します。
  • ⑪イミディエイト値とレジスタ間でNOT AND論理演算します。
  • ⑫レジスタ間でNOT AND論理演算します。

ロードストア命令

特定のアドレス(メモリまたはI/O)にリードまたはライトを行う場合に、ロードストア命令を使用して、アクセスを行います。アクセスするアドレスをレジスタに設定し、ロードストア命令1命令でアクセスを行います。

メモリからr0レジスタに“r1レジスタの値で示されるアドレス”からワード(32ビット)データをリードします。

図3

r0レジスタのワード(32ビット)データを“r1レジスタの値で示されるアドレス”にライトします。

図4

ダブルワード・ハーフワードサイズ・バイトサイズのアクセス命令も用意されています。

  • ●LDRD/STRD ダブルワードサイズ(64ビット)
  • ●LDRH/STRH ハーフワードサイズ(16ビット)
  • ●LDRB/STRB バイトサイズ(8ビット)

32ビットデータ定数と命令表現

MOV命令を使用して、イミディエイトオペランドを設定する場合、「8ビット定数を任意の偶数ビット回、右にローテートすることで表現できる値」です。命令形式では、Immed_8(イミディエイトデータ)とRotate_imm(ローテーション)を使用します。

例えば、r1レジスタに0xFF000000を代入する場合、0xFFを8回ローテーションすることで、表現することができます。

図5

上記の方法で設定値を設定できない場合は、リテラルプールを使用して、定数値をレジスタに設定します。この例では、0x12345678がLDR命令でr0レジスタに設定データをリードすることで、r0レジスタに設定されます。

図6

DCD擬似命令は、アセンブリ言語で、ワードデータを4バイト境界で設定された初期値で初期化を行います。

Thumb-2命令では、さらに効率を良くするために、16ビット定数ロード命令(MOVW命令・MOVT命令)を利用して、32ビット定数ロードを行います。

LDR擬似命令とは?

定数値のサイズを判断して、複数の命令を使用することは、プログラミングする上で問題となります。この問題を解決する為に、LDR擬似命令を使用します。

LDR擬似命令を使うことで、定数値のサイズに関係なくコーディングが可能となります。アセンブラは、イミディエイト値のサイズにより、MOV命令やリテラルプールを使用するか判断します。

図7

関数コールとスタックアクセス

関数コール(アセンブリ言語のサブルーチンコール)を行う場合、<label>のアドレスをpc(プログラムカウンタ)に設定し、戻りアドレスをlr(リンクレジスタ)に設定し、プログラムを実行します。

図8

しかし、関数コールがネスティングする場合、lrが破壊されるので、スタックに退避することが必要になりますので、次の手順で関数コールを行います。

  • ①処理で使用する、レジスタとlrをスタックに退避。
  • ②関数呼び出し処理を実行。
  • ③処理で使用したレジスタとpcをスタックから復帰。
  • lrの値がpcに復帰されることで、関数コールを行った次の命令から実行を再開します。
図9

C/C++言語から、アセンブリ言語の関数を呼び出す場合、スタックに退避・復帰を行うデータサイズは8バイト単位で行います。詳しくは、「AAPCS(ARMアーキテクチャのプロシージャコール標準)」を参照ください。

スタックの動作

r2=0x1234、r3=0x5678、r5=0x2000、sp=0x100Cの場合のスタックの動作を確認します。

図10

STMFD命令とLDMFD命令

STMFDとPUSH、LDMFDとPOPは同じ動作です。UAL(統一アセンブラ形式)では、PUSH/POPを使用します。

条件フラグと分岐命令

cpsr(プログラムステータスレジスタ)の条件フラグで、条件分岐等の動作を行います。

  • N=負数であることを示します。
  • Z=ゼロであることを示します。
  • C=符号なし演算でのオーバーフローの発生を示します。
  • V=符号あり演算でのオーバーフローの発生を示します。
図11

条件フラグを更新する命令

  • ①CMP r1, r0 ; r1-r0の結果を条件フラグに設定します。
  •  NZCV(条件コードフラグ)を演算結果に従って更新します。
  •  r1とr0が同じ値の場合は、条件フラグZ=1となります。
  • ②TST r1, r0 ; r1 AND r0の結果を条件フラグ設定します。
  •  NZCVを演算結果に従って更新します。
  •  r1レジスタとr0レジスタをAND論理演算結果が0の場合に、条件フラグZ=1となります。

設定することで条件フラグを更新する命令

  •  データ処理命令や乗算命令では演算結果を条件フラグに反映するか、しないかを選択できます。
図12
【条件フィールドと条件フラグの対応表】
ニーモニック 意味 条件フラグ
EQ 等しい Z=1
NE 等しくない Z=0
CS/HS キャリーセット/符号なし大または同じ C=1
CC/LO キャリーリセット/符号なし小 C=0
MI 負数 N=1
PL 正の数またはゼロ N=0
VS オーバーフロー V=1
VC オーバーフローでない V=0
HI 符号なし大 C=1 and Z=0
LS 符号なし小または同じ C=0 or Z=1
GE 符号付大または同じ N=V
LT 符号付小 N!=V
GT 符号付大 Z=0 and N=V
LE 符号付小または同じ Z=1 or N!=V
AL 常に成立

条件分岐命令

ループ処理を行う場合に、条件フラグの内容でプログラムの分岐先を変更することが必要になります。条件分岐命令を実行する前に、条件フラグを更新することが必要です。

図13

ソフトウェアタイマー処理での条件フラグ更新例

SUBS命令でループカウンタ(r0レジスタ)を減算処理し、条件フラグを更新します。SUB命令で実行した場合は、このプログラムは正しく動作しません。

図14

カレントプログラムステータスレジスタのリードライト

cpsr(カレントプログラムステータスレジスタ)にアクセスを行う場合は、MRS命令とMSR命令を使用します。

cpsrのアクセス命令

図15
cpsrの特定のフィールドにライトする命令が用意されています。
命令 フィールド プログラムステータスレジスタ
データ位置
cpsr_c 制御フィールドマスクバイト 0ビットから7ビット
cpsr_x 拡張フィールドマスクバイト 8ビットから15ビット
cpsr_s ステータスフィールドマスクバイト 16ビットから23ビット
cpsr_f フラグフィールドマスクバイト 24ビットから31ビット

cpsrのフィールドアクセス命令

図16

コプロセッサアクセス命令

Cortex-Aシリーズは、キャッシュやMMUの制御を行う場合に、コプロセッサに設定を行う必要があります。コプロセッサアクセス命令は、使用するプロセッサのマニュアル(*1)を参照して頂くことが必要です。

命令 動作内容
MRC コプロセッサレジスタからARMレジスタに移動します。
MCR ARMレジスタからコプロセッサレジスタに移動します。
【代表的なCP15(コプロセッサ15)レジスタと命令】
名称 略称 R/W 命令
システム制御レジスタ SCTLR R MRC p15, 0,<Rd>, c1, c0, 0
W MCR p15, 0,<Rd>, c1, c0, 0
補助制御レジスタ ACTLR R MRC p15, 0,<Rd>, c1, c0, 1
W MCR p15, 0,<Rd>, c1, c0, 1
コプロセッサアクセス
制御レジスタ
CPACR R MRC p15,0,<Rd>,c1,c0,2
W MCR p15,0,<Rd>,c1,c0,2

以下のマニュアルを参照ください。