矢沢久雄 グレープシティ アドバイザリースタッフ

 今回は,アセンブラの命令の種類と,アセンブラでプログラムの流れを表す方法を説明します。皆さんは,コンピュータには様々な機能があると思っていることでしょう。ところが,アセンブラの視点すなわちハードウエアの視点から見れば,コンピュータにはわずかなことしかできないことが分かります。「データの入出力」「データの演算」「プログラムの流れの制御」の3つだけです。これら3つの動作を組み合せて,高度で複雑なプログラムの機能が実現されているのです。本当かなと思われるかもしれませんが,この記事を読めば,納得できるはずです。

●アセンブラの命令の種類=CPUにできること

 CASL IIの命令(ニーモニック)を紹介しましょう。CASL IIの命令の種類は,COMET IIというハードウエアが持つCPUにできることを網羅したものです。命令の種類を丸暗記する必要などありません。上記の3つの動作に合わせて分類した表1~表3をざっと見ておいてください。

表1●データの入出力を行う命令

ニーモニック意味機能
LDLoaDメモリーからCPUへデータを読み込む
STSToreCPUからメモリーにデータを書き出す
LADLoad ADdressCPUのレジスタに値を設定する
PUSHPUSHスタックにデータを書き出す
POPPOPスタックからデータを読み込む
SVCSuperVisor CallI/Oとの入出力を行う

表2●データの演算を行う命令

ニーモニック意味機能
ADDAADD Arithmetic算術加算を行う
ADDLADD Logical論理加算を行う
SUBASUBtract Arithmetic算術減算を行う
SUBLSUBtract Logical論理減算を行う
ANDAND論理積(AND演算)を行う
OROR論理和(OR演算)を行う
XOReXclusive OR排他的論理和(XOR演算)を行う
CPAComPare Arithmetic算術比較を行う
CPLComPare Logical論理比較を行う
SLAShift Left Arithmetic算術左シフトを行う
SRAShift Right Arithmetic算術右シフトを行う
SLLShift Left Logical論理左シフトを行う
SRLShift Right Logical論理右シフトを行う
NOPNO Operation何もしない

表3●プログラムの流れを制御する命令

ニーモニック意味機能
JPLJump on PLus演算結果がプラスの場合に分岐する
JMIJump on MInus演算結果がマイナスの場合に分岐する
JNZJump on Non Zero演算結果がゼロでない場合に分岐する
JZEJump on ZEro演算結果がゼロの場合に分岐する
JOVJump on OVerflow演算結果が桁あふれの場合に分岐する
JUMPJUMP無条件で分岐する
CALLCALL主プログラムから副プログラムを呼び出す
RETRETurn副プログラムから主プログラムに戻る

 スーパーバイザ・コールは,SVCというニーモニックで示していますが,実際には,IN(I/Oからデータを入力する)やOUT(I/Oへデータを出力する)などのニーモニックが使われます(これはCASL IIの都合ですので気にしないでください)。演算命令の機能には,「算術~」というものと「論理~」というものがあります。2進数の最上位ビット(符号ビット)が1となっているデータを,「算術~」ならマイナスの値とみなし,「論理~」ならプラスの値とみなします。

 シフトとは,2進数の桁をずらす演算のことです。何もしないNOP命令は,プログラムで時間待ちをする場合などに使われます。何もしないのですが,演算命令に分類しておきました。

 各種の分岐命令は,直前の演算命令の結果に応じてプログラムの流れを分岐させます。CALLとRET命令は,副プログラムの呼び出しで使われます。今後の連載の中で具体的なサンプル・プログラムを示しますので,今は細かいことを気にしないで,全体の雰囲気をつかんでください。たった20数個の命令だけで,様々なプログラムを作れることに驚いてください。

●アセンブラの文法は1つだけ

図1●アセンブラの文法は「命令+目的語」だけ
 アセンブラというプログラミング言語の文法は,とても簡単です。文法は1つだけしかありません。「命令+目的語」だけです(図1[拡大表示])。これは,Give me money!(我に金を与えよ)のような英語の命令文の文法と同じです。命令(○○せよ)の部分には,ニーモニックを指定します。目的語(△△に□□を)の部分には,レジスタ名またはラベルを指定します。ニーモニックの種類に応じて,目的語がない場合も,1つの場合も,複数の場合もあります。目的語が複数の場合は,カンマ(,)で区切ります。例えば,GR1レジスタにA番地のデータを代入するには,以下のようにします。Aは,ラベルです。ラベルが何かは,すぐ後で説明します。

 「命令+目的語」すなわち「○○せよ+△△に□□を」を書き並べただけのものが,アセンブラのプログラムです。ただし,必要に応じて「ラベル」や「コメント」を付け加えることもできます。

 ラベルとは,アセンブラのプログラムのオペランドに名前(ラベル名)を付けたものです。この名前は,行のメモリー・アドレスを表しています。プログラムの中で123番地のような具体的なメモリー・アドレスの値を指定するのは面倒なので,ラベルを使うわけです。ラベルは,行の先頭に書きます。プログラムをマシン語に変換すると,ラベルの名前がその位置のメモリー・アドレスの値に置き換わります。

 コメントは,プログラマが任意に記入する注釈です。行の末尾にセミコロン(;)に続けて記入します。コメントを漢字で書くこともできます。コメントは,マシン語に変換されません。

 かつて,アセンブラ用の「コーディング用紙」といういうものが市販されていました。コーディング用紙とは,手書きでプログラムを記述するためのものです。ラベルとコメントを含めると,アセンブラのプログラムの1行の構成要素は,左から順に「ラベル,命令,目的語,コメント」の順になります。コーディング用紙では,命令のことを「オペコード」と呼び,目的語のことを「オペランド」と呼びます。表4は,100と200を加算した結果をANSというラベルが表すメモリー・アドレスに格納するプログラムをコーディング用紙に記述したものです。コメントを参考にして,プログラムの流れを追ってみてください。

表4●加算を行うプログラム

 
ラベルオペコードオペランドコメント
 LDGR1,A;GR1にA番地のデータを読み出す
 ADDAGR1,B;GR1とB番地のデータを加算する
 STGR1,ANS;加算結果をANS番地に格納する
 RET;主プログラムに戻る
ADC100;A番地に100というデータを格納しておく
BDC200;B番地に200というデータを格納しておく
ANSDS1;ANS番地にデータの格納場所を確保しておく
注:この連載では,プログラムの表記を一部省略する場合があります。

 表4に示したプログラムでは,オペコード欄にDCやDSという命令が使われています。これらは,CPUに動作を行わせるのではなく,メモリー上にデータ領域を確保する命令であり「擬似命令」と呼ばれます。DC(Define Constant)は,データ領域を確保して値を格納します。A DC 100なら,100という値が格納されたメモリー領域を確保し,それをA番地とします。DS(Define Storage)は,データ領域の確保だけを行い値を格納しません。ANS DS 1なら,メモリー領域1個分(16ビット)を確保し,それをANS番地とします。AやANSが何番地になるかを気にする必要はありません。

 ADDA GR1,Bの部分に注目してください。これは,GR1(値は100)とB番地のデータ(値は200)を加算するものです。加算結果である300は,どこに記録されるのでしょうか?実は,GR1に記録されるのです。GR1とB番地の加算結果が,再びGR1に記録されます。これは,アセンブラならではの特徴であり,ans = a + b のように,3つの変数を使って加算を行う高水準言語との大きな違いです。

●PCレジスタ,SPレジスタ,FRレジスタの役割

 COMET IIのCPUには,PC,SP,FR,GR0~GR7というレジスタがあります。これらの中で,アセンブラのプログラムの目的語(オペランド)欄に指定できるのは,SPとGR0~GR7だけです。PCとFRレジスタの値は,プログラムの実行中にCPUによって自動的に設定されます。

 PCレジスタ(Program Counter)は,プログラムの流れを制御するためのものです。アセンブラのプログラムの1行1行は,何番地かのメモリー・アドレスに格納されます。PCレジスタの値は,プログラムの起動時に1行目のメモリー・アドレスとなります。表4のプログラムなら,LD GR1,Aという行のメモリー・アドレスです。この行の命令の実行を終えると,CPUは,次の行(表4ならADDA GR1,Bの行)のメモリー・アドレスを自動的にPCレジスタに設定します。これによって,プログラムが1行目から順番に実行されて行きます。表3に示したプログラムの流れを変える命令を実行することでも,PCレジスタの値が自動的に設定されます。「自動的」とは,アセンブラのプログラムで直接PCレジスタに値を設定しないという意味です。

図2●FRレジスタの構造
 FRレジスタ(Flag Register)は,演算命令を行った結果が,ゼロ,マイナス,桁あふれ(オーバー・フロー)になったかを自動的に記録します。JPLやJMIなどの分岐命令は,FRレジスタの値に応じてプログラムの流れを変化させます。FRレジスタのサイズは3ビットであり,個々のビットでゼロ,マイナス,桁あふれを記録します(図2[拡大表示])。

 CPUは,2つのデータの大小を比較するときに,内部的に減算を行います。例えば,AとBを比較するなら,A - Bという減算を行います。AとBが等しければ,A - Bの結果がゼロになるので,FRレジスタのZero Flagが1になります。A>Bなら,A - Bの結果がプラスになるので,Sign Flagが0になります。A<Bなら,A - Bの結果がマイナスになるので,Sign Flagが1になります。比較結果は,Sign FlagとZero Flagでわかります(表5)。Overflow Flagは,演算結果が16ビットに収まらない大きな値になったとき,および右シフトで桁落ちが発生した場合に1になります。

表5●比較結果とFRレジスタの値

比較結果Sign FlagZero Flag
A=B01
A>B00
A<B10

 SPレジスタは,「スタック」と呼ばれるデータ格納領域をメモリー上に作るために使われます。スタックには,PUSH命令でデータを格納でき,POP命令でデータを取り出せます。データが格納されるメモリー・アドレスやラベルを指定しないでよいのが,スタックの便利なところです。

 スタックを作るためには,プログラムの最初で,スタックとするメモリー領域のアドレスをSPレジスタに設定しておきます。PUSH命令は,SPレジスタが指すメモリー・アドレスにデータを格納し,SPレジスタの値を自動的に-1します。POP命令は,SPレジスタが指すメモリー・アドレスからデータを取り出し,SPレジスタの値を自動的に+1します。

図3●SPレジスタが現在の読み書き位置を示す
 例えば,現在のSPレジスタの値が100番地なら,PUSH命令によって100番地にデータが格納され,SPレジスタの値は99番地に更新されます。次のPUSH命令では,99番地にデータが格納されます。現在のSPレジスタの値が99番地なら,POP命令によって99番地のデータが取り出され,SPレジスタの値が100番地に更新されます。次のPOP命令では100番地からデータが取り出されます。SPレジスタによってメモリー・アドレスが管理されたメモリー領域がスタックです(図3[拡大表示])。

●プログラムの流れ

 プログラムの流れには「順次進行」「条件分岐」「繰り返し」の3種類があります。これは,アセンブラに限らず,あらゆるプログラミング言語で同じです。

 順次進行とは,命令が記述された順に実行されていくことです。プログラムは,基本的に順次進行で流れて行きます。先に示したプログラムの流れも順次進行であり,上の行から下の行に向かってプログラムが流れます。

リスト1●条件分岐を行うプログラム
リスト2●繰り返しを行うプログラム
 条件分岐とは,何らかの条件に応じてプログラムの流れが変わることです。アセンブラでは,CPAまたはCPLという比較命令(内部的に減算を行ってFRレジスタを設定する命令)を実行した後で,その結果に応じてJPLやJMIなどの命令で条件分岐(内部的にFRレジスタの値を確認して特定のラベルのメモリー・アドレスをPCレジスタに設定する)が実現されます。例えば,GR1レジスタとA番地のデータを比較し,GR1>AならLBL1番地に分岐するプログラムは,リスト1[拡大表示]のようになります。JMI(Jump on MInus)は,FRレジスタにマイナスの結果が記録されているときに分岐を行います。JMIのオペランドには,分岐先のメモリー・アドレスを示すラベル(ここではLBL1)を指定します。

 繰り返しとは,プログラムの同じ部分を何度か繰り返して実行することです。アセンブラでは,何らかのレジスタで回数をカウントし,CPAまたはCPLで繰り返し回数に達していないことを確認して,JPLやJMIなどの命令でプログラムを前の行に戻すことで繰り返しが実現されます。リスト2[拡大表示]は,GR1レジスタで回数をカウントしながら10回の繰り返しを行うプログラムです。ここでは,GR1レジスタの初期値が0に設定されていて,N番地に10というデータが格納されているとします。

 アセンブラの命令の種類が「データの入出力」「データの演算」「プログラムの流れの制御」の3つだけであり,アセンブラの文法が「命令+目的語」だけであることを知りました。コンピュータとは,実にシンプルなものだと感じたでしょう。シンプルなコンピュータを使って,いかに高度で複雑なプログラムを作成するかは,プログラマの腕次第なのです。

 次回は,プログラムを主プログラムと副プログラムに分ける方法を説明します。どうぞお楽しみに!

■変更履歴
リスト1の2行目でLL1、リスト2の一番下でLBL3としていましたが、どちらも正しくはLBL1です。お詫びして訂正します。本文は修正済みです。 [2010/05/11]