●分岐命令とレジスタ
さて次は、分岐命令についてお話しします。CPUの命令は大きく分けて転送、演算、分岐に分けられます。まあ細かくほかにもありますが、大きく分けるとこの3つです。
転送、演算については、述べましたので、次に分岐命令の解説をします。
分岐とは、プログラムの流れを変えることです。通常、分岐が無ければ、処理はアドレスの順番に実行されていきます。分岐されれば、その流れが変わり、その分岐で指定されたアドレスへ処理が移ります。
さて、CPUは電源を投入後、メモリの先頭番地から実行していき、もし分岐がなければ、延々メモリの最終番地まで実行され、また先頭番地へ実行が戻ります。この「先頭に戻る」という動きは結構重要です。どういった理由で戻るのか。次のレジスタの表を見てください。
A | F |
B | C |
D | E |
H | L |
SP | |
PC |
分岐において重要なものにPCレジスタがあります。このレジスタはプログラムカウンタというレジスタです。CPUはメモリのコードやデータを読みながら実行されていくわけですが、当然、今実行しているアドレスを記憶しておかなければ、次にどこを実行するのかわかりません。そこで用意されているのが、このPCレジスタです。このレジスタもSP同様、機能レジスタになります。
手順 | 動作内容 |
---|---|
PCレジスタ→アドレスレジスタ | 現在のアドレスを記憶 |
PC+1→PC | PCレジスタをカウント |
(アドレスレジスタ)→命令解析レジスタ | 命令をメモリから読み込む |
命令実行 | 命令の処理 |
上の表のアドレスレジスタとは、CPUが内部処理に使用するものであり、アドレスの一時保存を行うためのものです。一般的にCPUは表のような手順を繰り返していきます。
そしてPCレジスタは実行していくごとに格納されているアドレス値を自動的に+1、加算していきます。このPCの値で、CPUは次にどのアドレスの命令を読んで実行するのかが決まるわけです。PCはこの場合16ビットであり、もしこの値が、FFFFhまでいき、次に+1加算すると、このカウンタは0000hへ戻ってしまいます。これが、メモリの先頭アドレスに処理が戻る理由なのです。
このことからCPUはPCの値通りに処理していくということが言えるわけですから、PC値を変えることはすなわち、次に実行されるアドレス指定できることになります。これが、分岐したことになり、分岐命令ではこのPCを変化させることを言います。
ニーモニック | オペレーション |
---|---|
JP nn | PC ← nn |
上の表の命令はジャンプ命令といい、nnで指定したアドレスをPCレジスタへ入れる処理をします。その結果、指定したアドレスへ処理が移り、プログラムの流れが変わる命令であるのです。
では実際に簡単な例を見てみましょう。
番地 | コード | アセンブリ言語 |
---|---|---|
0000h 0001h |
3Eh 0Ah |
LD A,10 |
0002h 0003h |
06h 16h |
LD B,20 |
0004h | 80h | ADD A,B |
0005h 0006h 0007h |
C3h 00h 00h |
JP 0000h |
●スタックと分岐命令
ここまでのジャンプ命令を利用して次のような流れを作ります。
番地 | プログラム |
---|---|
0000h : |
処理A |
0010h | JP 0023h |
0013h : |
処理B |
0020h | JP 0000h |
0023h : |
処理C |
0030h | JP 0013h |
ニーモニック | オペレーション |
---|---|
CALL nn | (SP) ← PC PC ← nn |
RET | PC ← (SP) |
CALL(コール)命令のオペレーションを見るとまず(SP)(SPが示すメモリアドレス)のメモリへPCのアドレスを保存してからPCを書き換えジャンプしています。そして、RET(リターン)命令は保存してある(SP)にあるのアドレスをPCへ戻しています。
これはどういうことが、次のプログラムを見てください。
番地 | プログラム | オペレーション |
---|---|---|
0000h : |
処理A | |
0010h | CALL 0023h | (SP)←PC(0013h) PC←0023h |
0013h : |
処理B | |
0020h | JP 0000h | 処理A |
0023h : |
処理C | |
0030h | RET | PC←(SP) (0013h) |
このようにCALL命令とRET命令はセットで使用されます。ジャンプする前にCALL命令の次のアドレスをスタックへ積み、今度はRET命令で、その値を戻す。これによりRET命令の場所では、戻るアドレスがスタックに積んであるので、直接戻る場所の指定をしなくてもよくなります。
この特徴を利用して、
番地 | プログラム | オペレーション |
---|---|---|
0000h : |
処理A | |
0010h | CALL 0033h | (SP)←PC(0013h) PC←0033h |
0013h : |
処理B | |
0020h | CALL 0033h | (SP)←PC(0023h) PC←0033h |
0023h : |
処理C | |
0030h | JP 0000h | 処理A |
0033h : |
処理X | |
0040h | RET | PC←(SP) |
このCALL、RET命令は大変便利で、同じ処理を繰り返すこともさることながら、呼び出すアドレスと、その処理内容さえ分かればどこからでも呼び出せ、戻る場所のアドレスは考える必要がないのです。
このようなことで、CALL、RET命令はジャンプ命令とはまた違った特徴を持つ分岐命令なのです。
●おまけ
「機械には押してはいけないボタンがある」っていうのはロボットものとかの定番(?)ですよね。実は以前、仕様書を見ていたときにZ80CPUにはHALTって命令が載ってました。あたしゃこわくて押した(!?)ことはないんですけど、この命令CPU動作を停止する命令らしいです。あっ間違っても、CPUが壊れるとか、自爆するとか(爆)いうわけではないですよ。それだとかなり怖い命令だ(笑)。
仕様書ではCPUの実行を停止させる命令となっています。まあたぶんCPUがただ止まるんでしょうけど、何故あるのかは不明な命令です。作った人が機械には付き物だ!って思っていたのかもしれませんがね(おぃおぃ)。そういえば・・・最新のCPUにもこのようなコードはあるんだろうか・・・・。