自作PC入門①～命令セット決定編～

# なにをするのか
計算機アーキテクチャやディジタル回路，アナログ回路等の知識を深めることを目的にして，コンピュータを「自作」します．

しかし「自作」という言葉は曖昧であり，これを厳密に定義しないと，どこまでも横着できてしまいます．
たとえば，シリコンのインゴットを切り出すところから始めても「自作」と言えますし，巷で言われる自作PCのように既存のパーツを組み立てるだけでも「自作」と言えます．
CPUの回路をHDLで記述し，FPGA上で動かすことも「自作」と言えます．
このプロジェクトでは，「自作」の定義を明確にするために，あらかじめ以下のルールを設定しました．

- コンピュータの各要素は，物理的に(手で触れられる実体として)自作する
- CPUを自作するのに使える部品は以下の通り
    - 汎用ロジックIC(74シリーズ，4000シリーズなど)
    - メモリIC(SRAM，EEPROMなど)
    - 抵抗やコンデンサ，ダイオード，トランジスタなどの回路素子
- CPUの論理回路は全てワイヤードロジックで作る
- 自分でプリント基板を設計して業者に発注するのは可

部品の仕様によってコンピュータの設計が制約されることを防ぐために，上記のような小さな粒度で「自作」することにしています．
このような粒度でコンピュータを製作することは，ここ半世紀の間で半導体の集積度が上がったことにより既に一般的ではなくなっていて，部品の入手などに困難が伴います．
したがって，上記の定義を大幅に外れない範囲で，例外的にこれ以外の部品を用いることがあります．

ワイヤードロジックというのは，命令デコーダや演算器の実装において，マイクロプログラムやルックアップテーブルなどを用いず，物理的な論理回路のみによって行う方針のことです．
この方針は，論理設計と物理設計の両方を難しくしますが，論理回路の学習という目的の上では有益です．

プリント基板を利用するのは，ユニバーサル基板の上で配線を行うという，あまり本質的でない，手間のかかる作業を省略したかったためです．

FPGAなどを用いず物理的にCPUを自作するという方針は，FPGAを使う方法は大学の実験の授業などで広く行われていて，あまり面白くないと思ったことによります．
プログラミングは趣味としては面白い部類だと思いますが，成果物に直接手で触れることが難しいという点で，手芸などに劣ります．


# 作業計画
以下のように作業を進めていくことを予定していますが，前後することがあるかもしれません．

1. CPUの作成
    - アーキテクチャの決定
    - VHDLによるCPUの論理設計
    - 論理回路のシミュレーション
    - CPUの物理設計
    - CPU基板の発注
    - 部品の実装(はんだ付け)
    - CPUのテスト

2. Cコンパイラの実装

3. 周辺装置の作成
    

# CPUのアーキテクチャの決定
## RISCかCISCか
問答無用でRISCを採用します．
今回はハードウェアを作るのにかかる労力が殺人的に大きいので，ハードウェアには単純な機能のみを任せ，それを組み合わせて複雑な機能を実現する努力はソフトウェアに任せることにします．

## アーキテクチャの概要
アーキテクチャの概要を以下のように決定しました．

- MIPSを参考にする
- ノイマン型，非パイプライン
- 汎用レジスタの幅は16ビット
- すべての命令は32ビットの固定長

MIPSを参考にしたのは，大学の計算機アーキテクチャの講義でMIPSが扱われていたということもありますが，共通化された命令形式や，プロセッサが持つべき最小限の機能とそれ以外の機能を分離するような思想が，回路の単純化に有利に働くと考えたからです．

大学の講義等では，MIPSはハーバード・アーキテクチャで説明されることが多いようですが，今回は，将来的に複雑なプログラムを動かしてテストすることを考えてノイマン型とします．
また今回RISCを採用した目的はあくまで回路の単純化であり，特に速度にこだわる必要はないのでパイプライン化は行いません．
汎用レジスタ幅を16ビットとしたのは，実装する上で大きすぎず，かつ他にインデックスレジスタ等を用意せずとも直接64kワード分のメモリ領域を参照することができるためです．

命令長については，命令デコーダを単純にするために固定長とし，一命令で即値を扱えることを考えて，レジスタ長の2倍である32ビットとしました．


## 命令セット
CPUが持つべき最小限の機能として，演算，メモリのロード/ストア，ジャンプ，割り込みの命令を設定します．
MIPSなどを参考にして，以下のように命令セットを決定しました．

- 演算命令

|命令|形式|操作|フラグのセット|
|--|--|--|--|
|XOR rd rs rt|R3|rd ← rs XOR rt|zero|
|XNOR rd rs rt|R3|rd ← rs XNOR rt|zero|
|NOR rd rs rt|R3|rd ← rs NOR rt|zero|
|NAND rd rs rt|R3|rd ← rs NAND rt|zero|
|OR rd rs rt|R3|rd ← rs OR rt|zero|
|AND rd rs rt|R3|rd ← rs AND rt|zero|
|ADD rd rs rt|R3|rd ← rs + rt|zero，sign，carry|
|SUB rd rs rt|R3|rd ← rs - rt|zero，sign，carry|
|SLA rd rs rt|R3|rd ← rs << rt|zero，sign，carry|
|SRL rd rs rt|R3|rd ← rs >>[^1] rt|zero|
|SRA rd rs rt|R3|rd ← rs >>[^2] rt|zero，sign，carry|
|XORI rd rs imm|R2I|rd ← rs XOR imm|zero|
|XNORI rd rs imm|R2I|rd ← rs XNOR imm|zero|
|NORI rd rs imm|R2I|rd ← rs NOR imm|zero|
|NANDI rd rs imm|R2I|rd ← rs NAND imm|zero|
|ORI rd rs imm|R2I|rd ← rs OR imm|zero|
|ANDI rd rs imm|R2I|rd ← rs AND imm|zero|
|ADDI rd rs imm|R2I|rd ← rs + imm|zero，sign，carry|
|SUBI rd rs imm|R2I|rd ← rs - imm|zero，sign，carry|
|SLAI rd rs imm|R2I|rd ← rs << imm|zero，sign，carry|
|SRLI rd rs imm|R2I|rd ← rs >> imm (論理シフト)|zero|
|SRAI rd rs imm|R2I|rd ← rs >> imm (算術シフト)|zero，sign，carry|

- メモリ命令

|命令|形式|操作|
|--|--|--|
|LD rd rs imm|R2I|rd ← [rs + imm]|
|ST rd rs imm|R2I|[rs + imm] ← rd|

- ジャンプ命令

|命令|形式|操作|
|--|--|--|
|JP rs imm|RI|PC ← rs + imm|
|BZ rs imm|RI|PC ← rs + imm if zero = 1|
|BS rs imm|RI|PC ← rs + imm if sign = 1|
|BC rs imm|RI|PC ← rs + imm if carry = 1|

- 割り込み命令
 
|命令|形式|操作|
|--|--|--|
|IRET|N|割り込みからの復帰|
|(割り込み信号)|-|割り込みアドレスへジャンプ|

なお，ここでrd，rs，rtは汎用レジスタ，immは即値，PCはプログラムカウンタを表すものとします．
また，MIPSに倣い0番の汎用レジスタはゼロレジスタとし，さらに他の汎用レジスタのうち1本は入出力レジスタとします．

## 機械語コードの概要
CPUが命令を理解するためには，命令と対応する機械語コードを設定しなければなりません．

ここでは，大まかな命令コードを以下のように決定しました．
![optype.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357326/9b6e5cac-1c66-8a0e-55cd-a189fcce9bc0.png)

やや変則的で無駄がありますが，命令デコーダの設計が簡単になるように設定しました．

まず先頭の3ビットを見ることで命令の形式を容易に判別できるようになっています．
命令中にrs，rt，rdで表される汎用レジスタは3ビットで指定され，この情報はすべての命令形式で共通の位置に格納されます．
rs，rt，rdの部分は3ビットであるため，指定できるレジスタは8本に制限され，さらにそのうち2本はゼロレジスタと入出力なので，汎用レジスタは6本です．
演算命令等でALUが行う演算を指定するのは，図中でALUと書いている部分の6ビットです．
ジャンプ命令の条件は図中でconditionと書いている部分で，無条件ジャンプと条件ジャンプ(zero，sign，carry)を単純に処理できるように4ビットで指定します．
即値は命令の下位16ビットに格納します．

図中で空白になっているビットは，同じ形式の命令を区別するために適宜利用します．

# まとめ
今回は，自作PCのCPUの命令セットと，それに対応する機械語コードの概要を決定しました．
次回は，今回決めた命令を実現する具体的なアーキテクチャ，マイクロアーキテクチャの設計を行います．