mikecat が 2022年12月05日19時11分16秒 に編集
初版
タイトルの変更
TD4の命令を実行できるCPU「Kageki」
タグの変更
TD4
CPUの創りかた
自作CPU
74シリーズ
ロジックIC
Kageki
メイン画像の変更
記事種類の変更
製作品
ライセンスの変更
(CC BY 4+) Creative Commons Attribution CC BY version 4.0 or later
本文の変更
++[自作CPU Advent Calendar 2022](https://qiita.com/advent-calendar/2022/diycpu) 5日目++ 74シリーズのロジックIC10個で、『[CPUの創りかた](https://book.mynavi.jp/ec/products/detail/id=22065)』で題材となっているCPU「TD4」で定義された命令を実行できるCPU「Kageki」を作成した。 # 名前の由来 TDといえば『[探偵歌劇 ミルキィホームズ TD](https://www.nicovideo.jp/watch/1420604904)』だよね…というところから。 4人組が活躍する物語なので、TD4の「4」の部分にも対応している。 ~~[かげきしょうじょ!!](https://www.nicovideo.jp/watch/so38970269) は関係ない。~~ # TD4で定義された命令 TD4では、以下のデータを扱う。 * Aレジスタ (4ビット) * Bレジスタ (4ビット) * フラグ (1ビット) * 入力ポート (4ビット) * 出力ポート (4ビット) * プログラムカウンタ (4ビット) TD4では、以下の命令が定義されている。 (出典:[CPUの創りかた TD4](http://xyama.sakura.ne.jp/hp/4bitCPU_TD4.html)) |命令|機械語|実行後のフラグ|動作| |---|:-:|:-:|---| |`MOV A, Im`|`0011 mmmm`|0|即値をAレジスタに格納する| |`MOV B, Im`|`0111 mmmm`|0|即値をBレジスタに格納する| |`MOV A, B`|`0001 0000`|0|Bレジスタの値をAレジスタに格納する| |`MOV B, A`|`0100 0000`|0|Aレジスタの値をBレジスタに格納する| |`ADD A, Im`|`0000 mmmm`|キャリー|Aレジスタの値と即値の和をAレジスタに格納する| |`ADD B, Im`|`0101 mmmm`|キャリー|Bレジスタの値と即値の和をBレジスタに格納する| |`IN A`|`0010 0000`|0|入力ポートから読み込んだ値をAレジスタに格納する| |`IN B`|`0110 0000`|0|入力ポートから読み込んだ値をBレジスタに格納する| |`OUT Im`|`1011 mmmm`|0|即値を出力ポートに出力する| |`OUT B`|`1001 0000`|0|Bレジスタの値を出力ポートに出力する| |`JMP Im`|`1111 mmmm`|0|無条件で、指定のアドレスに絶対直接ジャンプを行う| |`JNC Im`|`1110 mmmm`|0|フラグが0ならば、指定のアドレスに絶対直接ジャンプを行う| # TD4で定義された命令の考察 TD4で定義された命令を良く観察すると、`JNC Im` 命令以外の命令は全て、 「機械語を `rrss mmmm` とおくと、`ss` で表されるデータと `mmmm` の和を `rr` で表される場所に格納する」 と表現できることがわかる。 `ss` で表されるデータは、以下のものである。 |`ss`|データ| |:-:|---| |`00`|Aレジスタ| |`01`|Bレジスタ| |`10`|入力ポートから読み込んだ値| |`11`|ゼロ固定| `rr` で表される格納先は、以下のものである。 |`rr`|格納先| |:-:|---| |`00`|Aレジスタ| |`01`|Bレジスタ| |`10`|出力ポートに出力する値| |`11`|プログラムカウンタ| また、フラグについても、実行後のフラグが0固定となっている命令は全て `mmmm` または `ss` で表されるデータが0固定であるため、加算を行ってもキャリーは発生せず、常に「命令実行後のフラグは加算で発生したキャリーとする」としてよい。 これだけを実装すると、`JNC Im` 命令の機械語は `1110 mmmm` なので、 「(無条件で) 入力ポートから読み込んだ値と `mmmm` の和をプログラムカウンタに格納する」 となる。 しかし、`JNC Im` 命令の動作を実現するには、この動作を * フラグが0の場合のみ値をプログラムカウンタに格納する * 入力ポートから読み込んだ値を無視し、ゼロを `mmmm` に加算するようにする というように変えなければならない。 これを Kageki においてどのように実現したかは、後述する。 # 回路図 KiCad で回路図を作成した。  Kageki は、以下の部分からなる。 * 入出力ポート `ports` * TD4で定義された入力ポートと出力ポート * 電源・クロック・リセットの入力 * プログラムROMに出力するアドレスと、プログラムROMから入力されるデータ * レジスタ `regs` * 各種レジスタ (プログラムカウンタ・出力ポートに出力する値を含む) * `JNC Im` 命令用のロジック * 計算 `logic` * データと制御信号を受け取り、格納するデータとフラグを出力する * 表示 `led` * 各種状態をLEDで出力する ## 入出力ポート  各種ポートを用意している。 入力ポートは、1MΩの抵抗でプルアップしている。 [共通仕様](https://elchika.com/article/ef1e092a-7bbf-4666-9aae-8d777b58e30f/)ではROMのアドレスは8ビットだが、Kageki のプログラムカウンタは4ビットしかないため、ROMを有効活用できるよう、アドレスの上位4ビットをディップスイッチで設定できるようにした。 ## レジスタ  4ビットの各データを 74HC161 (カウンタ) を用いて、また1ビットのフラグを 74HC74 (D-FF) を用いて格納している。 値を書き込まないとき、レジスタと出力ポートはカウントアップしない設定に、プログラムカウンタはカウントアップする設定にしている。 さらに、74HC138 (デコーダ) を用い、命令の `rr` の部分を書き込み先に変換している。 書き込み先がプログラムカウンタのとき、さらに 74HC00 (2入力NAND) を用い、以下の処理を行っている。 * ユニット `U7D` により、書き込み先がプログラムカウンタであることを表す信号を正論理に変換している。 * 書き込み先がプログラムカウンタでないとき、ユニット `U7C` の入力の1本が `0` となるため、`U7C` の出力は `1` となり、ジャンプは行われない。 * この信号は、後で入力ポートから読み込んだ値を無視する処理にも用いる。 * ユニット `U7A` により、`ss` の下位ビットを反転し、ユニット `U7B` に供給している。 * このビットは、`JMP Im` 命令では `1`、`JNC Im` 命令では `0` である。 * このビットが `1` のとき、`U7B` の入力の1本が `0` となるため、`U7B` の出力は `1` となり、`U7C` の出力が `U7D` の出力によって決まるようになる。すなわち、書き込み先がプログラムカウンタであれば無条件にジャンプする。 * このビットが `0` のとき、`U7B` の出力はフラグによって決まる。フラグが `1` のときは `U7C` の入力の1本である `U7B`の出力が `0` となり、`U7C` の出力は `1` となる。すなわち、ジャンプは行わない。 この処理により、`JNC Im` 命令の「フラグが0の場合のみ値をプログラムカウンタに格納する」を実現している。 ## 計算  入力されるデータをから加算する値を 74HC153 (セレクタ) により命令の `ss` に基づいて選択し、74HC283 (加算器) により命令の `mmmm` の部分との加算を行う。 また、書き込み先がプログラムカウンタであることを表す正論理の信号を 74HC153 のイネーブルに入力することで、書き込み先がプログラムカウンタのときは常に `0` と `mmmm` を加算するようにしている。 この処理により、`JNC Im` 命令の「入力ポートから読み込んだ値を無視し、ゼロを `mmmm` に加算するようにする」を実現している。 ## 表示  * プログラムカウンタ * 命令 * Aレジスタ * Bレジスタ * 出力ポートに出力している値 * フラグ の値を、LEDを用いて出力する。 LEDはそれぞれの信号に抵抗を介して (トランジスタなどを用いず) 直結している。 # 使用したIC Kageki では、以下のICを使用している。 |IC|機能|個数| |---|---|:-:| |74HC161|4ビットカウンタ|4| |74HC74|2回路D-FF|1| |74HC138|3ビットデコーダ|1| |74HC00|2入力NAND|1| |74HC153|4入力セレクタ|2| |74HC283|4ビット加算器|1| 合計10個のICを用いている。 この数は、『CPUの創りかた』のキャッチフレーズにある「IC10個」と合致する。 # 基板の制作 [Elecrow](https://www.elecrow.com/) で安価に製作可能である 100mm×100mm 以内に収まるように基板を設計し、発注した。 部品を実装した完成形が以下である。   # 動作の様子 以下の動画は、 TD4 のサンプルプログラムとして知られている[ラーメンタイマー](http://xyama.sakura.ne.jp/hp/4bitCPU_TD4.html#program)を Kageki で実行した様子である。 出力ポートの最上位ビットに [2-way Buzzer Board](https://elchika.com/article/c55891ed-5a5f-4355-bf36-8a9f5ca6cd37/#h_2-way%20Buzzer%20Board) の auto 端子を接続し、同ビットが `1` になったらブザーが鳴るようにした。 @[youtube](https://www.youtube.com/watch?v=3rozR9H0RiQ)