CPU の創りかた(TD4)をブレッドボードで作ってみた話

やっとこさ作れました(∩´∀`)∩

もはや本だけ読んで、実際に「作ってみよう作ってみよう」と思いつつ、はや十年くらい。

ずっと放っておいたわけですが、人生一回くらい CPU っぽいものをハードウェアで作ってみようと、一念発起しました。

動いている様子はこちら。

この記事では制作する段階で得た知識や苦労した点など、思いを書いていこうと思います。

ブレッドボードで作りたいと思ったモチベーション

はんだ付け怖い

という不安だけなのです。

ユニバーサル基板で配線してミスとか、はんだ不良とかありそうで、自信がなく「あ、これ絶対自分のはんだ付けのせいだ」となったら、モチベがガタ落ちしそうだったからです。

とは言え、はんだ付けは怖くないと思いますし、とりあえず基本的な結線はジャンパワイヤなら確実だろうと思っただけだったりします。(ブレッドボードは取り回しがしづらいこともありますし)

作った人(私)の前提知識

どの程度の知識の人が今回の TD4 ブレッドボード版を作ったかですが

  • 今はWeb エンジニアな人
  • 論理回路はちょっとわかる
    • 半加算器、全加算器、NOT/OR/AND/XOR とか
  • ハードウェアも電気も チットモワカラナイ
    • 電気の話とかは中学、高校くらいでやったけど、ほぼ忘れ気味
  • プログラミング経験は普通

では、代替品や苦労した点、実際に使った部品リストなどを書いていこうと思います。

最後の方に各モジュールを拡大して撮った写真もあるので、よければどうぞ。

使った代替品(オリジナルと異なる点)

秋葉原を歩いて回っていたのですが、入手が難しいことや、サボるために本書からは多少アレンジしました。(とはいえ数点ですが)

  • 74HC161 -> 74HC163
    • 本書のレジスタとプログラムカウンタ、はてまた出力を司る大切な カウンタ IC
    • aitendo さんで TC74HC161AP が見つかりはしたのですが、正直お店が開いている時間も、立地的にもちょっと個人的には厳しかったので、東芝さんのデータシートにある 74HC161 と併記されている 74HC163 を使うことにしました。
  • ROM(8 DIP SW x16) -> Arduino UNO R3
    • 本書では 8 DIP SW を 16個並べる方式で ROM を作っているのですが、これまたブレッドボードで配線するとなると地獄だと思ったので、ここはサボって Arduino UNO R3 を使いました。
    • これは先駆者の方がいらっしゃって、真似ることにしました。
    • 参考: TD4ブレッドボード版できた!

ちなみに ROM を DIP SW でやりたい人向けに書いておくと、現在 74HC154 (4-to-16 Line Decoder) は入手が難しいようで、74HC138 2個を使えば同じようにできるようです。ロジックが合っていれば代わりも作れるなんてロジック IC の良いところですね。(IC の個数増えてるけど)

4bit-CPU : TD4の解説(SlideShare) から 74HC154 を 74HC138 2個で代用する回路図を引用させていただきます。

苦労したところ

とにかく、クロック回路から74HC163(カウンタ IC)の入力のところで苦労しました。

本書では 1Hz と 10Hz のクロック回路を組むわけですが、それを 74HC163(カウンタ IC) に入力すると正しくカウントアップしてくれない … 1個ずつ上がっていってくれるはずが、たまーに 2 カウントアップしたり、4 カウントアップしたりする … という事象です。

ただでさえ、作ったクロック回路の回路図(ループしている回路)を見て、「俺は正しい回路を組めているのか・・・?」と半信半疑な状態です。

果てはクロック回路と 74HC163 だけを繋いで、74HC163 の出力を LED で観測しつつ、Arduino UNO を使って似非オシロスコープのようにして電圧を観測するという方法を使っていました。(精度は全然ダメかもしれませんが、Schmitt trigger as an oscillator という記事があって、それを真似しながらクロック回路からの波形を見るという方法を取りました)

原因はただ単に使っていた AC アダプタが悪く、5V1A のアダプタではなく、5V2A のアダプタに変更したらサックリ動いたのですが(´・ω:;.:…

あとは、命令デコーダの結線ミスを見つけたりしました。デコーダのところの結線、結構大変です。

ROM (Arduino UNO R3) で利用しているコード

TD4ブレッドボード版できた! で掲載されているコードそのままです。(rom[] の内容は動かしたいプログラムによって違います)

これに加えて補足説明をすると、D1 と D0 番のピンを使わない理由としては、Arduino は D0, D1 のピンをシリアルに利用しているそうで、これはまた別の記事で書こうかなと思います。

unsigned char rom[] = {
  // Aレジスタのスライドアニメーションを
  // Bレジスタが1クロック遅れで追いかけるプログラム
  B00110001, // MOV A,0001
  B01000000, // MOV B,A
  B00110011, // MOV A,0011
  B01000000, // MOV B,A
  B00110111, // MOV A,0111
  B01000000, // MOV B,A
  B00111111, // MOV A,1111
  B01000000, // MOV B,A
  B00111110, // MOV A,1110
  B01000000, // MOV B,A
  B00111100, // MOV A,1100
  B01000000, // MOV B,A
  B00111000, // MOV A,1000
  B01000000, // MOV B,A
  B00110000, // MOV A,0000
  B01000000, // MOV B,A
};

void setup() {
  DDRB = DDRB | B00001111;
  DDRC = DDRC | B00001111;
}

void loop() {
  // アドレス入力 D5 D4 D3 D2 番ピン(右が最下位ビット)
  // データ出力   D11 D10 D9 D8 A3 A2 A1 A0 番ピン(右が最下位ビット)
  unsigned char addr = (PIND & B00111100)>>2;
  PORTC = (PORTC & B11110000) | (rom[addr] & B00001111);
  PORTB = (PORTB & B11110000) | ((rom[addr] & B11110000)>>4);
}

早めのまとめ

後に続くのは、各モジュールの写真と部品リストなので、ここで一旦まとめてしまいます。

これ素直にユニバーサル基板にはんだ付けした方が楽だったんと違うのか!?

というレベルでした。結線の確認を行っているときに、ブレッドボードを前後左右から確認するわけですが、ジャンパワイヤが邪魔で邪魔で、とにかく数え間違いが無いように神経をすり減らすという、本末転倒な事態が起きていたりして。

けど、「ここまで結線したら動かすまで根性でやるわ」みたいな無駄な意地を発揮して完成まで至りました。

ちなみに今はもったいないですが、バラしちゃったので今度はユニバーサル基板とかで作って、保存できるようにしたいと思います。

「CPUの創りかた」の著者さんが書かれている通り、CPU 自作というのは非常にロマンがあることで作っている最中も「自分は CPU を作っているんだ。しかもハードウェアで!」という感じで奮い立たされるものがありました。

この本がベースになって、FPGA などで組む際にもとても心強い基礎力になりそうです。

長々と書きましたが、ここまで読んでくださりありがとうございます。

後は部品リストと写真、工作する際に便利な道具をお楽しみください(´・ω・)ノシ

部品リスト

今回作成に利用した部品リストは以下の通りです。抵抗は適量なのですが、とりあえずクロック回路とリセット回路用は必須です。

名称必要個数
抵抗1/4W 100Ω2
抵抗1/4W 1kΩ10
抵抗1/4W 10kΩ9
抵抗1/4W 100kΩ4
抵抗1/4W 3.3kΩ1
抵抗1/4W 33Ω1
   
電解コンデンサ 10μF 16V2
無極性(両極性)電解コンデンサ 10μF 16V1
   
LED適量
出力用 4
Aレジスタ用 4
Bレジスタ用 4
リセット用 1
クロック用 1
   
TC74HC10AP (14 pin)1
TC74HC14AP (14 pin)1
TC74HC32AP (14 pin)1
TC74HC74AP (14 pin)1
TC74HC153AP (16 pin)2
TC74HC163AP (16 pin)4
TC74HC283AP (16 pin)1
  
ブレッドボード(大きめなら更に少なめにできるはず)9
  
4連ディップスイッチ1
  
タクトスイッチ2
トグルスイッチ2
DC5V安定化電源(秋月電子 GF12-US0520)1
HiLetgo® 電源モジュール1
  
ジャンパワイヤ 15 cm (オス – オス/Male – Male)数十本
ジャンパワイヤ 30 cm (オス – オス/Male – Male)取り回し用なので数本
  
Arduino UNO R3 (ROM 用)1

各モジュールの写真

リセットとクロック回路

ALU とレジスタ

命令デコーダ

OUTPUT LED と レジスタの LED

ROM

工作するときに便利だった道具

とにかく楽になったと思ったのは下記の2つです。

サンハヤト ピンそろった ICS-01

ネーミングが小林製薬さんみたいですが、ブレッドボードに挿す前にこれを通しておくとスッと入って作業が楽です。

DIP-IC引き抜き工具(IC引抜冶具) ICP-20

こちらは引き抜くときに使う工具です。手で抜くのも方法としてはあるのですが、割と簡単に IC のピンは曲がりますし、繰り返していると金属疲労で割と簡単に折れます(折ったことないですが、めっちゃ折れそうになる)

なので、こういう工具で丁寧に引き抜いてあげることで、IC の足をキレイに保つことができます。