プログラム制御
LDM 01010 ADM 01011 ADM 01100 STM 01101ついでに番地も記号化します。01010 から順に a0, a1, a2 と書くことにします。すると、上のプログラムは次のようになります。a0,a1 などは番地を表す記号なので「記号番地」と呼びます。
LDM a0 ADM a1 ADM a2 STM a3このように命令や番地を記号化したプログラムを記号プログラムとかアセンブリ言語プログラムと呼びます。
命令の種類 実行する値(メモリの番地)から構成されています。そこで、命令を11ビットで表現することとし、上位3ビットで命令の種類、下位8ビットで命令が実行する値を記録することにします。LOD を 100、ADM を 101 で表現すると、先のプログラムは
100 01010 101 01011 101 01100 101 01101となります。このように 0,1で表現されたプログラムを、機械語プログラムとよびます。CPUはこの機械語命令を読みだしながら、計算処理を行います。
PS 番地のメモリの値をレジスタ IR に読み出す。 PS を一つ増す IR に読み出した値に従い、命令を「実行」する 以上を繰り返すレジスタの値を一つ増すには、PS をカウンタ(計数器)として動作させることになります(カウンタ回路の詳細はここでは省略します)。命令を「実行」するには、IR レジスタの先頭3ビットをチェックし、100 なら LDM 、101 なら ADM の処理を行う事になります。この方式を、プログラム蓄積(Stored Program)方式、あるいはノイマン(最初にこの方式を紹介した人の名前)方式と呼びます。命令の実行で「PSレジスタの値を変更する」ことで複雑な制御が可能になります。
0: 初期設定 1: 演算処理1 2: 演算処理2 3: JP 1 //1番地にジャンプこの、ジャンプ命令の「からくり」は意外と簡単です。ジャンプ命令の実行で(演算命令のようにWを変更するのでなく)PS レジスタの値を変更すればよいのです。JP命令では命令で指定した値(番地)を PS レジスタに設定します。プログラム制御では PS レジスタの番地の命令を実行しますから、PS レジスタの値を変更すれば、次は変更した番地の命令を実行します。
現在のPS | 実行する命令 | 次のPS |
0 | 初期設定 | 1 |
1 | 演算処理1 | 2 |
2 | 演算処理2 | 3 |
3 | JP 1 | 1 |
1 | 演算処理1 | 2 |
2 | 演算処理2 | 3 |
0: Wを10にする 1: Wをc0番地に記録する 2: 演算処理1 3: 演算処理2 4: c0を1減らす。(このとき結果が0になったら ZF が1にセットされる) 5: ZFが0のとき1番地へジャンプする。そうでなければ、次の命令に進む 6:c0 はメモリの特定の番地(たとえば8番地)を利用します。最初に 0 ,1番地の命令で c0(8番地)を10に設定します。4番地の命令で c0 を一つ減らし、この結果0になったら 演算回路により自動的に ZF が1にセットされます。命令5では ZFが0(1でない)のとき、PSを変更して1番地にジャンプします。ZFが1のときは条件が成立しませんからジャンプは行われず、5番地以後の命令に進みます。ZF が 0 とき、a 番地にジャンプする命令を
0: LDI 10 //W<-10 1: STM c0 //c0<-W 2: 演算処理1 3: 演算処理2 4: DEC c0 //c0-- 5: JNZ 2 //if not ZF jump 1 6:c0 が 0 になるまでJNZ 2 で2番地に戻り、10回繰り返すと DEC命令で ZF が1になり、次の JNZ 命令ではジャンプをせずに6番地に進みます。
命令 | 意味 |
DEC a | a番地を1減らす |
JP a | 無条件にa番地にジャンプ |
JZ a | ZFが1ならa番地にジャンプ |
JNZ a | ZFが0ならa番地にジャンプ |
JS a | 負ならa番地にジャンプ |
JNS a | 負でなければa番地にジャンプ |
0: LDI 0 //W <- 0 1: STM s //s <- W 2:L1:LDM s //W <- s 3: ADM a //W <- W + a 4: STR s //s <- W 5: DEC b // b-- 6: JNZ L1 //if notZF goto 2 7:L2:JP L2 //動的停止 8: a: 5 //加える値 9: b: 10 //加える回数 10: s: 0 //結果
#include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { int a,b,s; s = 0; a = 10; b = 5; L1: s = s + a; b--; if(b != 0) goto L1; printf("%d\n",s); return 0; }通常、C言語では繰り返しは goto 文を使わずにつぎのように while や for を利用してプログラムをします。 goto 文を利用したプログラムはプログラムの流れが理解しにくく、間違いを起こしやすいからです。ただし、CPUには for や while の命令はなく、コンパイラが 条件付き goto(Jump) 命令に置き換えているのです。
int _tmain(int argc, _TCHAR* argv[]) { int a,b,s; s = 0; a = 10; b = 5; do{ s = s + a; b--; } while ( b != 0); printf("%d\n",s); return 0; }
if (条件) A;と書きます。右下は、無条件ジャンプを組み合わせた例で
if (条件) A else B ;の流れです。条件付実行は条件付ジャンプ命令と無条件ジャンプを組み合わせることで、実行が実現できます。
LDI -5 STM a //a=-5 SBI 0 //a > 0 ? JNS L1 LDI 0 //a = -a SBM a STM a L1:同じような処理を C言語で行います。printf( )は結果の確認用です。
int _tmain(int argc, _TCHAR* argv[]) { int a; a = -5; if (a > 0) goto L1; a = -a; L1:printf("%d\n",a);//確認 return 0; }