自作CPU Advent Calendar 2022 5日目
74シリーズのロジックIC10個で、『CPUの創りかた』で題材となっているCPU「TD4」で定義された命令を実行できるCPU「Kageki」を作成した。
名前の由来
TDといえば『探偵歌劇 ミルキィホームズ TD』だよね…というところから。
4人組が活躍する物語なので、TD4の「4」の部分にも対応している。
かげきしょうじょ!! は関係ない。
TD4で定義された命令
TD4では、以下のデータを扱う。
- Aレジスタ (4ビット)
- Bレジスタ (4ビット)
- フラグ (1ビット)
- 入力ポート (4ビット)
- 出力ポート (4ビット)
- プログラムカウンタ (4ビット)
TD4では、以下の命令が定義されている。
(出典:CPUの創りかた TD4)
命令 | 機械語 | 実行後のフラグ | 動作 |
---|---|---|---|
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Ωの抵抗でプルアップしている。
共通仕様では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 で安価に製作可能である 100mm×100mm 以内に収まるように基板を設計し、発注した。
部品を実装した完成形が以下である。
動作の様子
以下の動画は、 TD4 のサンプルプログラムとして知られているラーメンタイマーを Kageki で実行した様子である。
出力ポートの最上位ビットに 2-way Buzzer Board の auto 端子を接続し、同ビットが 1
になったらブザーが鳴るようにした。
投稿者の人気記事
-
mikecat
さんが
2022/12/05
に
編集
をしました。
(メッセージ: 初版)
ログインしてコメントを投稿する