はじめに
未経験からWebエンジニアを目指した際に基本情報技術者試験を受験しました。その際にCPUの機能や5大装置の関係性を学びましたが、なんとなく暗記しただけで実際には、あまりイメージ出来ていなかったと思います。就職活動も終わり、勤務開始まで少し時間がありましたので、改めて学習をしてみたいと思いました。
現在は 放送大学の講義を参考にインプットを行なっています。アウトプットとrubyの学習のために擬似環境を作ってみたいと思います。rubyという高水準言語を用いて、低水準言語であるアセンブラを表現することは逆行的ですが、先にrubyやJAVAなどの学習を行なった人の理解の手助けになれば嬉しいです。
(rubyもコンピュータの基本動作についても初心者のため、誤った内容があればぜひご教授いただきたいです)
### 目次
1 → 4(流し読み) → 2 → 3 → 4の順番で読んでいただくと、読みやすいと思います。
コンピュータの動作原理
コンピュータは、主記憶装置であるメモリからCPUのレジスタにプログラムやデータをロードして、演算を行います。一つ一つの命令を命令サイクルに基づいて処理していきますが、詳しくはCPUなどのメソッドを作成する際に記述します。
COMET2について
COMET2とは情報処理技術者試験の中で扱われる仮想的なコンピュータの名称です。CASL2というCOMET2を動かすために考案されたアセンブリ言語で動作します。CPUを動作させる命令セットが28個しかなく、レジスタやメモリの数も少ないので、学習のためにはちょうどいいと思い、簡易的なCOMET2を作成することを目標にします。(完全なCOMET2シミュレータを作成するまで頑張るつもりはありません。。。)
CPUの構成
COMET2のCPUは「プログラムレジスタ(プログラムカウンタ)」、「スタックポインタ」、「フラグレジスタ」、及び8つの「汎用レジスタ」で構成されています。サイズはフラグレジスタのみ3bitで、他は全て16bitです。
プログラムレジスタ(PR、別名プログラムカウンタ)
プログラムレジスタには次に実行する命令のメモリアドレスが格納されます。
メモリは揮発性のデバイスであるため、プログラムは不揮発性の補助記憶装置(HDDやSSD)などに保存されます。OSの働きで補助記憶装置からメモリにプログラムがロードされると、一連のプログラムの実行開始位置が自動的にプログラムレジスタにセットされます。
基本的に命令は上から順番に実行されますので、命令の実行が終わるとプログラムカウンタの値は自動的に1つ増加され、次のアドレスを指すようになります。
条件分岐や繰り返しを行う場合には、特別な命令によりプログラムカウンタの値を任意の値に変更することで、任意のアドレスに移動し実行順序を制御します。
スタックポインタ(SP)
OSがメモリにプログラムをロードする際、メモリ上にはプログラム領域、データ領域、スタック領域が割り当てられます。各領域の詳細はメモリの構成にて説明します。
このスタック領域は主に汎用レジスタの値を一時的に退避する目的で使われ、スタックの最上段のアドレスを保持するのがスタックポインタです。データの書き込み、取り出しは下記命令で実行され、データの取り出しは必ずスタックポインタが指す最上段から行われます。
- PUSH命令・・・汎用レジスタからスタック領域へのデータの書き込み。スタックポインタの値を一つ減らす。
- POP命令 ・・・スタック領域から汎用レジスタへのデータの取り出し。スタックポインタの値を一つ増やす。
フラグレジスタ(FR)
フラグレジスタは、容量3ビットの小さなレジスタで、ゼロフラグ(ZF)、サインフラグ(SF)、オーバーフローフラグ(OF)の3つで構成され、それぞれがフラグのON/OFFを1/0で表します。演算、比較、データの読み書きなどを行なった結果が自動的に設定されます。
それぞれのフラグがONとなる条件は下記の通りです。
- ゼロフラグ・・・計算結果が0のとき、ONになる
- サインフラグ・・・計算結果がマイナスのとき、ONになる
- オーバーフローフラグ・・・計算結果が16ビットの容量を超えたとき、ONになる
このフラグレジスタの状態を参照することで、下の表のような条件付きジャンプ命令を実行し、プログラムの流れを変えることもできます。
汎用レジスタ(GR)
メモリからロードしたデータを一時的に保存しておくレジスタで、略称のGRはGeneral Resisterの略です。高水準言語における変数のように扱われ、データやメモリアドレスなどを保存することができます。ただし、COMET2においてメモリアドレスを保存することができるのは、GR0を除くGR1~GR7で、このような使い方をできる汎用レジスタのことを指標レジスタと呼びます。
メモリの構成
COMET2のメモリ容量は65536語(65536 * 2バイト = 131,072バイト)で、約131KBです。アドレスは0~65535番地までありますので、1つの番地に1語(16ビット)のデータを格納できます。
OSがプログラムをロードする際には、メモリは「プログラム領域」、「データ領域」、「スタック領域」という特定の領域に区切られて使用されます。
-
プログラム領域・・・プログラムコードが格納される領域です。プログラム領域に格納されているデータは全て機械語として扱われます。CPUのプログラムレジスタには、プログラム領域のアドレス値が入ることになります。
-
データ領域・・・プログラムを実行する際に、値を設定したり、汎用レジスタからデータがロードされる領域です。
-
スタック領域・・・CPUのスタックポインタの説明の際に記載した領域です。汎用レジスタの値を一時的に退避する目的で使われます。
アセンブラの命令の構造
アセンブラの命令は「オペコード」と「オペランド」から構成されています。
- オペコード・・・「〜せよ」という動作を表す
- オペランド・・・「〜を」という動作の対象を表す
COMET2では28の命令セットがありますが、それぞれについては次回の記事にて記述します。
ニーモニック
機械語を人間にわかりやすくアルファベットに置き換えたものです。これまでにいくつかの命令を記述してきましたが、その命令はニーモニックで表しています。機械語は1と0の数列で表しますが、これを人間に分かりやすいように、機械語に対して1対1で対応付けしたものになります。
1つ例を挙げます。2進数の機械語で「0010 0100 0001 0010」という命令は何を表しているか分かりますでしょうか。
前半8ビットがオペコードで「ADDA」を表し、後半8ビットは「GR1,GR2」のオペランドを表しています。
つまり「GR1とGR2の算術加算を行え」という命令になります。
ニーモニックと機械語は1対1で対応付けされていますので、今回擬似環境を作る上ではニーモニックの段階で学習を進めたいと思います。(機械語の段階まで考えると1語命令と2語命令の違いやGR0を指標レジスタとして使えない理由など深く学ぶことができるようですが、余力があったら学習してみたいと思います。)
終わりに
今回作成する擬似環境の概要を記載するだけで1つの記事が終わってしまいました。次回から実際にrubyを用いてオブジェクトを作っていき、CPUやメモリに対する理解をさらに深めていきたいと思います。