コンピュータの仕組み
おおまかに説明すると、コンピュータは、"計算" を行う CPU と、記憶を行うメモリと、外部との間で入出力を行
う入出力装置、そして、それらをつなぐ情報の通路であるバスからなっている。
実際には、高速化のためにキャッシュメモリを搭載したり、ビデオカード
(ディスプレイをつなぐための入出力装置)は汎用のバス以外のものでつないだり、様々な工夫がなされているが、
基本的なつくりはこれだけである。
- CPU (Central Processing Unit) は、マシン語と呼ばれる言語で書かれた命令の列(プログラム)を順次メ
モリから読み込みながら、その通りの動作を行う。内部に、レジスタという、
値を記憶する場所がいくつか、それと、現在実行している命令のアドレスを記
憶するプログラムカウンタが存在する。
- メモリ (Memory)は、データを記憶する場所であり、1バイトごと
に番地(アドレス)がふられている。2バイト、4バイトといった大きさのデー
タを格納する時には、指定された番地から連続して2つ、4つの箱が使われる。
メモリに記憶される内容は、プログラムとデータの2種類に分けられる。
- 入出力装置 (Input/Output device) は、ハードディスクや CD, DVD, ディスプ
レイ、キーボード、マウス、ネットワーク、スピーカーなどの外部の部品と
の間でデータをやりとりするための機器である。
- バス (Bus)は、CPU, メモリ、入出力装置の間でデジタルなデータ
をやりとりするための情報の通路であり、マザーボードの上に実現されており、
チップセットにより制御されている。バスという言葉は、複数の機器で共有さ
れるデータの通信路という、もっと広い意味で使われることもある。
ごくごく単純なコンピュータのシミュレータを使って、この仕組みを理解しよ
う。
このシミュレータの構成 (括弧内は、実行画面上での名称)
- CPU は、32ビットのレジスタ(Register)を1本と4ビットのプログラムカ
ウンタ(PC)を持っている。
- メモリは、プログラム用メモリ(Program)とデータ用メモリ(Data)に分か
れており、アドレス空間の大きさも単位になるデータの大きさも異なる。これ
は、通常のコンピュータとは違うところである。個々の命令の長さを1バイト
にするため、このような設計になっている。
- プログラム用のメモリは、情報を格納する単位は1バイトであり、アドレ
ス空間は16の大きさをしている。すなわち、1バイトのデータを格納できる
箱が16個あり、0 から 15 までの番号が振られている。アドレスは、4ビッ
トで指定できる。(よって、プログラムカウンタは4ビットである。)アドレ
スを表記する時には、16進法で、0 から f で表す。
- データ用のメモリは、情報を格納する単位は4バイト(すなわち32ビット)で
ありアドレス空間は8の大きさをしている。すなわち、4バイトのデータを格納
できる箱が8個あり、0 から 7 までの番号が振られている。アドレスは、3ビッ
トで指定できる。CPU のレジスタ、および、データ用メモリに格納された32ビッ
トの0,1の列は、2の補数表現の整数としてのみ扱われる。すなわち、-2の31
乗から、2の31乗-1 までの数として扱われる。
- 入出力装置として、ディスプレイ(Display)だけがつながっている。入力
はできない。入力の代りに、実行開始時のデータ用メモリの値を指定する。
- マシン語の命令は、それぞれ1バイト(すなわち8ビット)である。(実
際の CPU で使われるマシン語では、このように命令長がそろっているとは限ら
ない。)個々のマシン語の命令は、上位4ビットと下位4ビットに分けられ、
上位4ビットは命令の種類、下位4ビットは引数を指定している。
マシン語について
- 命令の種類は、上位4ビットで指定する。16 種類あり、下記の表では、
0 から f までの16進法で表記している。
- 個々の命令の種類には、表のように名前がついている。
- 命令の引数は、下位4ビットで指定する。引数は、データ用メモリ、ある
いはプログラム用メモリのアドレスを意味している。命令の種類により、引数がど
ちらのアドレスであるか、あるいは、全く引数をとらないかが決まっている。
- HALT, PRINT は引数をとらない。下位4ビットは常に0である。(下の表で n。)
- JUMP, JUMPZERO, JUMPGR, JUMPGE は、プログラム用メモリのアドレスをとる。
(下の表で p。)
- それ以外は、データ用メモリのアドレスをとる。
(下の表で d。)
- データ用メモリのアドレスの場合、アドレスの指定には3ビットしか必要な
いので、下位4ビットの一番上のビットがあいている。このビットは、以下に述
べる間接アドレッシングに用いられる。
- このビットが 0 なら、下位3ビットが指定する 0 から 7 の数をアドレス
として用いる(直接アドレッシング)。
- このビットが 1 なら、データメモリの、下位3ビットが指定する 0 から 7 の数のアドレス
に格納されている値をアドレスとして用いる(間接アドレッシング)。
- アセンブラで記述する時には、命令の名前の後にスペースをあけて、その
後に引数を16進法で記述する。ただし、間接アドレッシングの時には、引数の
前に* をつける。
- 例えば、ADD 4 と書けば、34, JUMPGE c は ac、HALT は f0、STORE *7 は 2f というマシン
語の命令(コード)となる。
命令の種類 | 命令の名前 | 引数 | 説明 |
1 | LOAD | d | 引数で指定されたアドレスのデータをレジスタにコピーする。 |
2 | STORE | d | レジスタの値を引数で指定されたアドレスにコピーする。 |
3 | ADD | d | レジスタの値に引数で指定されたアドレスのデータを加える。 |
4 | SUB | d | レジスタの値から引数で指定されたアドレスのデータを引く。 |
5 | MUL | d | レジスタの値に引数で指定されたアドレスのデータを掛ける。 |
6 | DIV | d | レジスタの値を引数で指定されたアドレスのデータで割る。 余りは切捨て。 |
7 | JUMP | p | 引数で指定されたアドレスに飛ぶ。 |
8 | JUMPZERO | p | もしレジスタの値が 0 なら引数で指定されたアドレスに飛ぶ。 |
9 | JUMPGR | p | もしレジスタの値が正なら引数で指定されたアドレスに飛ぶ。 |
a | JUMPGE | p | もしレジスタの値が正か 0 なら引数で指定されたアドレスに飛ぶ。 |
b | PRINT | n | レジスタの値を画面(Display) に表示する。 |
c | APRINT | d | 引数で指定されたアドレスの値を画面に表示する。 |
d | CLEAR | d | 引数で指定されたアドレスの値を0 にする。 |
e | INC | d | 引数で指定されたアドレスの値を1増やす。 |
f | HALT | n | プログラムの実行を終了する。 |
使用方法:
最上部のラジオボタンが示す様に、edit と execute の2つのモードがある。
まず、edit モードで、Program の左の欄にプログラムのアセンブラ・コード、
Data にデータ用メモリの初期値を書き込む。あるいは、右上の
Samples, Advanced Samples のメニューからサンプル・プログラムを選ぶこともできる。
後者は、間接アドレッシングを用いたサンプル・プログラムが入っている。
英文字は、大文字、小文字のどちらでも構わない。また、最
下部の Machine Code の所に、マシン語のバイト列として入力することもでき
る。
プログラムとデータができたら、ラジオボタンで execute モードを選ぶ。
すると、アセンブラ・コードがマシン語に変換されて右の欄と最下行に表示され、onestep, go,
reset の3つのボタンが使用可能となる。onestep で1命令実行、go で halt
命令により終了するまで実行する。reset で最初の状態に戻る。ただし、go でいつ
までたっても halt に到達しない場合のことを考え、go も 500ステップ進
んで halt に到達しなければ、止まる様にしてある。続けて実行したければ、
再び go を押せばよい。
edit モードに戻れば、プログラムやデータを変更することができる。
サンプルプログラムの説明:
samples:
- sum0: data[0], data[1], data[2], data[3] の和を表示する
- sum1: data[3], data[4], data[5] の和を求め、それが data[0] より大きければ 1 (data[2]) を、そうでなければ 0 (data[1]) を表示する。
- sum2: 0 から 100 (data[1]) までの和を求め、表示する。
- fukuri: 10000 (data[3]) 円を 利率 1.03 (data[4]/data[5]) で 100 (data[2]) 年貯金した
時の毎年の元金+利息 を表示する。
- prime: 素数の一覧表を作成する。このプログラムは終了しない。
Advanced samples:
- sum0: data[1]から data[7] までの和を表示する。
- sum1: data[3]から data[7] までの和を表示する。より正確には、 data[data[0]]から data[data[1]] までの和を表示する。
- prime: 素数を、data[3], data[4],... に格納していく。このプログラムは終了しない(エラーで終わる)。
次のようなプログラムを書いてみてはいかがでしょう:
- data[0] * data[1] + data[2] を計算、表示する。
- data[0] と data[1] の2乗の和を求め、表示する。
- 0, 1, 2, ... と無限に表示する。
- 0, 1, 2, ..., 20 と20(data[1] の値)まで表示する。
- 0 から 100 (data[1]) までの2乗の和を求め、表示する。
- 10000 (data[3]) 円を 利率 1.03 (data[4]/data[5]) で 何年貯金したら2倍になるか求める。
バグ等は、できるだけ具体的に書いて以下のアドレスまでお知らせください。
Hideki Tsuiki,
tsuiki@i.h.kyoto-u.ac.jp