命令は、処理内容を表すオペコード(operation code)と、処理対象データを表すオペランド(operand、被処理データ)からなる。
例えば、プロセッサ内のレジスタXに数値10を転送する機械語命令を考える。
レジスタ'X'と数値'10'のどちらもデータ転送という処理の処理対象であるが、通常はレジスタのようなマイクロプロセッサに固有のものを指し示す部分はオペコードの中に入れて「レジスタXへのデータ転送」という処理とし、'10'のように命令を使用するときに変化する部分のみがオペランドとされる。
つまり、「レジスタXへのデータ転送」という処理を示すオペコードと、Xに転送されるデータを示すオペランド(上の場合は'10')によって命令が表される。
なお、これはRISC型プロセッサとCISC型プロセッサでは異なり、CISC型であってもプロセッサの種類によって状況は異なっている。
通常マイクロプロセッサは、まずオペコードを読み込んで処理内容を認識し、もしもオペランドを必要とする処理であれば、次にオペランドを読み込む。
オペランドの処理方法は、命令によって異なる。
ある命令ではオペランドは数値として扱い、別の命令ではメモリアドレスとして扱う。
また別の命令ではオペランドをメモリアドレスとし、そのメモリアドレスの内容をメモリアドレスとしてその内容を演算する、といったことも考えられる。
このようにオペランドの扱いは、命令の処理内容次第である。
一般的なマイクロプロセッサでは、オペコードとオペランドは連続したメモリアドレスから読み込む。 そこで、オペコードとオペランドを併せた命令のバイト数によって1バイト命令、2バイト命令などというように命令を区別することがある。 1バイト命令の実行ではメモリから1バイトだけを読み込み、2バイト命令の実行では、メモリから2バイトを読み込む。
機械語プログラムは1と0の羅列であり、人間にとってあまりにも分かりにくいので、ビットパターンを4ビットずつに区切って16進数に直すことがあるが、これも機械語プログラムと呼ぶことがある。
しかし、'10001100'といったビットパターンやこれを16進数に直した'8C'などがどの命令を表すのかは、人間にはすぐには分からない。
そこで各命令に、人間にとって意味があり、その命令が行う処理を類推できる文字列を対応付ける。この文字列をニモニック(mnemonic)と呼ぶ。そしてニモニックによって表したプログラムをアセンブリ言語(assembly language)プログラムと呼ぶ。
アセンブリ言語と機械語は1対1に対応している。したがって、アセンブリ言語プログラムから機械語プログラムへの変換は単純な置換操作である。この変換を行うツールをアセンブラ(assembler)と呼ぶ。
BASIC、C、FORTRANといった高級プログラミング言語(high-level programming language)では、コンパイラ(compiler)によって高級言語プログラムを機械語プログラムに翻訳する。
そのため、優秀なコンパイラを使用することで、質の悪いプログラムにもコンパイラが最適化を施して優れた機械語プログラムに翻訳することもできる。
(ただし、アルゴリズム的に劣悪なプログラムでは、いくら最適化を施しても優れたアルゴリズムに基づくプログラムと対等になることはない)
一方、アセンブリ言語と機械語は1対1に対応しており、通常はアセンブラは最適化は行わない。
したがって、アセンブリ言語によるプログラミングの優劣は、そのまま機械語プログラムの実行速度や実行効率の優劣となる。
[ラベル:] 命令ニモニック [オペランド]ラベルは省略可能である。 またオペランドを必要とする命令では、オペランドを記述できる。 命令ニモニック中やオペランド中の','(カンマ)は、命令を見やすくするために使用しても構わないが、アセンブルの際に削除される。
例 |
元のオペランド | 括弧を外したオペランド |
---|---|
($30) | $30 |
((WORK)) | WORK |
例 |
オペランド | 種別 | 値 |
---|---|---|
'A' | arg | 65(文字'A'の文字コード) |
'12' | arg | 49(文字'1'の文字コード) |
''' | arg | 39(文字'''の文字コード) |
'\' | arg | 92(文字'\'の文字コード) |
例 |
オペランド | 種別 | 値 |
---|---|---|
$30 | arg | 16進数(10進数の48) |
-123 | arg | 10進数 |
例 |
オペランド | 種別 | 値 |
---|---|---|
WORK | label | 100(ラベルのアドレス(10進数)) |
WORK+1 | label | 101(100+1) |
WORK-$10 | label | 84(100-16) |
5+WORK | label | 105(5+100) |
最初に取り除いた括弧が種別に戻されることを考慮して、最終的にオペランドには以下のような種別が与えられる。
例 |
オペランド | 与えられる種別 | オペランドの値 |
---|---|---|
'a' | arg | 97(文字'a'の文字コード) |
(' ') | (arg) | 32(文字' 'の文字コード) |
$30 | arg | $30(10進数の48) |
($30) | (arg) | $30(10進数の48) |
WORK | label | 100 |
(($30)) | ((arg)) | $30(10進数の48) |
(WORK+5) | (label) | 105 |
X | X | 0/td> |
(Y) | (Y) | 0 |
例 |
---|
org $30
以降の命令を$30(10進数の48)以降のメモリアドレスに格納する
|
例 |
---|
db 130
(10進数の)130を書き込む
|
例 |
---|
dw 130
(10進数の)130を2バイトのデータとして書き込む
|
db疑似命令とdw疑似命令は、初期値をもったデータの記述、あるいはプログラムの作業領域の確保に利用できる。
以下の例では、メモリアドレス$40(10進数の64)に2バイトのデータ保存領域(ラベルはWORK)とメモリアドレス$42(10進数の66)に1バイトのデータ保存領域(ラベルはWORK1)を確保している。
例 |
org $40 WORK: dw 0 WORK1: db 0
例えば、読み込んだ1行が
WORK: LD AC, -25 # ACに-25を代入であるとする。まず、コメントを削除すると以下のようになる。
WORK: LD AC, -25ここで、':'が存在するので':'より前、すなわち'WORK'はこの行のラベルである。 この行のラベルが'WORK'であることをアセンブラ内部に記録して、行からラベルを削除すると以下のようになる。
LD AC, -25','を空白に置換して
LD AC -25となる。
例えば、前処理後の行データが
LD AC -25であるとき、空白によって区切ると以下の3つの単語
'LD' 'AC' '-25'に分割される。プログラム中に'LD', 'AC'といったラベルがなければ'LD'と'AC'は変更なくそのままである。 '-25'は10進数であるので、オペランドとして認識され、種別を表す'arg'に置換される。 すなわち、上の3つの単語はそれぞれ
'LD' 'AC' 'arg'に置換される。これを空白をはさんで連結すると
'LD AC arg'となる。この文字列'LD AC arg'を命令定義ファイルによって定義された命令の書式と比較する。 ここでは、前述の命令'LD AC, arg'にマッチする(命令書式中の','(カンマ)は無視し、連続する複数の空白は単一の空白に置換されることに注意)。 命令'LD AC, arg'は2バイト命令と定義されているので、読み込んだ命令は、オペコード'10001100'の2バイト命令であり、オペランドは十進数の'-25'と翻訳される。
注意
命令のニモニックである'LD'やレジスタを指す'AC'といった特別な意味をもつ単語と同じ文字列をラベルとして使用してはならない。 本来ラベルとして使用してはならない文字列をラベルとして使用してもアセンブラ自体のエラーとはならないが、該当する命令がない旨のエラーになる。 |