|
|
プログラム例 |
仮想コンピュータ プログラム例
| 1. | 加算 (123 + 100)
メモリ 15 番地に 123、14 番地に100 をストアしておきます。 アキュムレータは先ず 15 番地のデータ (123) を読み込み、次に 14 番地のデータ (100) を加算し、 出力ポートに出力してプログラムが終了します。 実行すると出力ポートは “11011111” になります。これは 10 進数にすると 223 です。 | |||
| 2. | 10 までの整数の加算
メモリ 15 番地に 10 をストアし、アキュムレータはクリアして 0 にしておきます。 アキュムレータに 15 番地のデータ(10)を加算し、次に 15 番地のデータをデクリメントします。 データは 9 になり、0 ではありませんから、プログラムは LOOP というラベルのあるアドレスにジャンプ(分岐)します。 再びアキュムレータに 15 番地のデータ(9)を加えて、アキュムレータは 19 になります。 15 番地のデータをデクリメントし… ということを 0 になるまで繰り返すと、 アキュムレータには 10 までの整数の和が残りますから、これを出力ポートに出力して終了します。 「10 までの整数の加算」 と書いていますが、実際には 10 + 9 + 8 +…+ 2 + 1 という計算をしています。 | |||
| 3. | 最大値を出力する
長いプログラムに見えますが、“STORE” はデータの準備をしているだけで、実際のプログラムは“SET X” からです。 11〜15 番地に納められているデータの中から、最も大きい値を見つけて出力しますが、 こういう問題はコンピュータが得意とするところです。 一連のデータを処理する場合は、インデックスレジスタを使います。 まずインデックスレジスタにデータがある最初の番地、11 をセットします。 これで "READ X" 命令は、インデックスレジスタのデータ (11) の番地にあるデータ (144) を読み込みます。 とりあえずこれを出力ポートに出力しておいて、次にインデックスレジスタをインクリメントします。 この結果、インデックスレジスタが 0 になったら L2 にジャンプしてプログラムは終了しますが、今は 12 ですから、 次に "CMP X" 命令を実行します。 "CMP" 命令はアキュムレータからメモリのデータを引きますが、アキュムレータの値は変化しません。 もしアキュムレータの値 (今は 144) よりメモリのデータ (この場合は 12 番地の 178)の方が大きければ、 キャリーフラグが 1 になります。 JCC 命令は、キャリーフラグが 0 なら L1 に分岐します。 1 なら次の "JMP L0" 命令によって L0 にジャンプします。 今はキャリーフラグは 1 ですから、分岐先の READ 命令で比較の結果大きかった方のデータがアキュムレータに読み込まれます。 これを出力ポートに出力して、同じ処理をインデックスレジスタが 15 になるまで繰り返し、次に 0 になれば修了です。 出力ポートはデータの大小によって何度か書き換えられますが、プログラムが終了したときには最大値が書き込まれています。 | |||
| 4. | 表の集計 (103 + 54 + 92 + 36)
表のデータの総和を計算するプログラムで、 データは C 〜 F 番地にストアしておきます (データは 10個まで増やすことができます)。 データのアドレスを示すためにインデックスレジスタを使用し、ADD IX 命令を使って順次加算していきます。 加算後インデックスレジスタをインクリメントしますが、 1111 をインクリメントして 0000 になるとプログラムは終了します。 | |||
| 5. | かけ算 (21 × 11)
掛け算のプログラムです。 コンピュータですから 2 進数で計算しますが、このプログラムを理解するために、 2 進数での掛け算はどうすればいいのかを考えてみます。 といっても、次のように、ふだん行っている10 進数の掛け算と比べてみると、まったく同じ、というより、 むしろ 2 進数の方が簡単です。
プログラムは、これとまったく同じことをコンピュータに行わせています。 この例では被乗数 21 を 15 番地に、乗数 11 を 14 番地にストアします。 13 番地には積を累算するため、あらかじめクリアしておきます。 まず、乗数 (14 番地:1011) を右にシフトして、最下位ビット (キャリーフラグに入る) が 1 であれば 被乗数 (15番地:10101) を 13 番地に加えて (最下位ビットが 0 なら加えずに)、被乗数を左にシフトします。 右にシフトされた乗数が 0 になれば計算終了です。 プログラムを実際に仮想コンピュータに入力して、掛け算が進行していく様子を確認して下さい。 なお、このプログラムでは、答えはメモリ 13 番地にありますが、出力できていません。 出力するためのプログラムを書き加えるには、記憶容量がもう少し (1バイト…) 必要です。 | |||
| 6. | 大きい数の加算 (12345 + 43210)
この仮想コンピュータは 8 ビットですが、大きい数の計算もできます。 例として、12345 + 43210 を計算します。 12345 は 2 進数にすると "00110000 00111001"、43210 は "10101000 11001010" ですから、 これを 2 つに分けてそれぞれ 14、15 番地と 12、13 番地に STORE してもいいし、 12345 を 256 で割った商 48 と余り 57、同じく 43210 を256 で割って、商 168 と余り 202 を、
という風に書いても、もちろん、どちらでも構いません。 まず、下位 8 ビット同士を加算して和を 11 番地に書き込み、次に上位 8 ビット同士を加算しますが、 その前に、今の加算でできたキャリーを加えなくてはなりませんので、 アキュムレータをクリアして、キャリーが 1 であればインクリメントした上で 12番地を加算し、 更に 14 番地のデータを加算して、和を 10 番地に書き込んでいます。
を削除すると、和は "11011000 00000011"、10 進数では 55299 となって、256 だけ少なくなってしまいます。 この仮想コンピュータではキャリーの処理が面倒ですが、一般の CPU にはキャリーも一緒に加算する命令があります。 | |||
| 7. | 車のうっかりミス防止
これは 論理回路のページの 「車のうっかりミス防止回路」 と同じ働きをするプログラムです。 入力ポートの 0 ビット目にはドアのセンサからの信号が、 1 ビット目にはエンジン、 2 ビット目はキー、 3 ビット目にはライトの信号が接続されています。 それぞれの動きと 0, 1 の対応は論理回路ページの 表 の通りです。 また、出力ポートの 0 ビット目はブザーに接続されていて、 これが 1 になればブザーが鳴るようになっているものとします。
このプログラムの考え方は、「論理回路」で作ったものとは少し違います。
入力ポートの 0 ビット目にはドアの信号が接続されていますから、 ドアが開かない限り(1 にならない限り)ブザーをならす必要はありません。 入力ポートのデータをアキュムレータに読み込んで、右にシフトすると最下位ビットがキャリーフラグに入りますから、 キャリーフラグが 0 であればLOOP に分岐して入力命令を繰り返します。 ドアが開けば、エンジンがどうなっているかをチェックするために、もう一度右にシフトしてキャリーフラグを検査します。 エンジンが動いていればブザーは鳴らさなくていいので、この場合も LOOP に分岐します。 ドアが開いてエンジンが止まったとき、キーやライトがどうなっているかを調べるために、 15 番地のデータとの論理積(AND)を取ります。 15 番地のデータは #00000011 で、アキュムレータのデータはこのときには 2 度シフトされていますから、 2 ビット目、3 ビット目に接続されているキーとライトのデータは 0、1 ビット目に移動しています。 従って、これと #00000011 との論理積をとると、キーとライトのデータがどちらも 0 であればアキュムレータはゼロになって、 やはりブザーは鳴らさなくていいので LOOP に分岐します。 キーとライトのデータのうち、少なくともひとつが 1 であれば、 #00000011 との論理積をとると アキュムレータの値はゼロになりません。 この場合はブザーを鳴らさなくてはなりませんから、出力ポートの 0 ビット目を 1 にするために 先ずアキュムレータをクリアして、その後インクリメントして出力ポートに出力します。 このプログラムは、仕組みが理解できたら Clock を少し早めにして (動作表示も止めて)、 "RUN" をクリックして下さい。 入力ポートをマウスでクリックして、"00001001" や "00000101"、"00001101" にすると、出力ポートが "00000001" になって停止します。 このように、コンピュータは単に数値演算ばかりでなく、論理演算もでき、 入力ポートにセンサの信号、出力ポートにはブザーの他ライトやモーターなどのアクチュエータ (actuator) を接続すれば、 さまざまの機械、機器を制御することができます。 | |||
| 8. | タイマ
コンピュータが、命令を実行するのに一定の時間がかかることを利用したタイマです。
Clock を 64Hz に、動作表示を OFF にして実行し、入力ポートをクリックすると、 約 10 秒後に出力ポートが "00000001" になって停止します。 このプログラムでは、まず 14 番地のデータが 15 番地にコピーされています。 その後、14 番地のデータを読んで、それが 0 になるまでデクリメントを繰り返すことで時間を稼ぎ、 0 になったら 15 番地をデクリメントして L1 に戻りますから、ここで 2 重の時間稼ぎをしています。 従って、最初の疑似命令 "STORE" で設定する値が 10 の時は約 10 秒のタイマですが、 2 倍の 20 にすると 22 倍の、約 40 秒のタイマになります。 多重ループにすることで、長時間のタイマを短いプログラムで作ることができます。 たとえば、トースターのボタンを押してから 150 秒後にヒーターのスイッチを切る、 というような制御を、コンピュータに行わせることができます (いまどき、こんな単純なことはしていないでしょうが…)。 | |||
| 9. | 数当てゲーム (?)
ゲームづくりに挑戦しました!
クロックを早めにしておいて実行し、入力ポートに何か数値をセットします。 その数値がある数より大きければ、コンピュータは "#11111111" を出力し、 小さければ "#00000000" を出力します。 ある数と等しくなれば、その数値を出力して停止します。 「ある数」は 15番地にストアしている "#00110100" ですから、 この仮想コンピュータでは正解が見えていますし、 そうでなくても当て方は簡単で、とてもゲームといえる代物ではありません。 しかしまあ、メモリが 16バイトでは、できることといえばこの程度です…。 |