
『CPUの創りかた』を読んで4bit CPUを製作しました
昨年は、これまでおこなってきたアイヌ語の学習の集大成として、 アイヌ語機械翻訳アプリ「tunci」 という、Transformerを本格的に応用した機械学習のプロジェクトに取り組みました。tunciは無事完成し、 U-22プログラミングコンテスト においては経済産業大臣賞という名誉ある賞もいただけることになりました。 しかしながら、製作の過程においては自分の低レイヤーにおける情報処理の理解の浅さ(とくにGPUがどうやって行列演算をしているのか全く理解していない)を痛感することになり、Hugging Face Transormerライブラリの枠をはみ出たより高度な実装をするには、低レイヤーの知識が欠かせないことを実感しました。 低レイヤーなら手始めにCPUからだろうということで、昨年末から 『CPUの創り方』(マイナビ出版) をちまちまと進めており、4ヶ月ほど経ってようやく完成させることができたので、ここに備忘録としてまとめたいと思います。 同書の初版は2003年(私が1歳のとき!)に出版されており、改定されることなく33刷りまで発行されているなど、もはや古典的な名著です。同書内で製作することになる「TD4」を実際に実装したブログ記事などは他にもたくさんありますが、紹介されている中のいくつかの部品はもはや生産が終了されているものもあるため、そこにも触れつつまとめられたらとおもいます。 動作する様子 最も基本的なプログラムの1つであるLEDチカチカです。OUT命令で、2ビットのLEDを左右に順番に動かしていきます。10Hzで動作させると、かなり滑らかに見えます。 ラーメンタイマーの動作の様子です。正確に3分15秒が経過した時点で、一番手前のLED(4ビット目)が点灯しています。 製作の流れと詰まった点 最初はブレッドボード上で動作を確認した 私はこれまで電子工作にほとんど触れたことがなかったため、1章から飛ばすことなく読みました。当然ながらはんだ付けもしたことがなかったので、最初はブレッドボードを使って回路を組み立て、記載されているとおりに動作するかを確認しました。発振回路を作るためのコンデンサーの充電・放電の過程や、それぞれのICの入力に対する出力結果などは、ブレッドボード上で実際に組み立てながらひとつずつ動作を確認して進めました。 同書の中では著者自身も「電子工作未経験者は最初に入門書を読むことをおすすめする」と言及していましたが、現時点ではCPUを作ること以外にはあんまり興味がわいていなかったので、どうしてもわからなかったところはその都度ググって解決していました。 74HC14とコンデンサー・抵抗器を組み合わせて、ブレッドボードで発振回路の動作を試す様子。この時点では抵抗器に複数の種類があることを知らず、不必要にも酸化金属皮膜抵抗を使っていました。千石電商の地下一階入口から一番近い所にあったためです。 ROMとCPU本体については、ブレッドボードで組み立てることができないほど複雑だったため、細かく分解して動作を確認しました。ROMについては、2アドレスを上位3ビットだけ動作確認しました。 74HC138と74HC04、DIPスイッチを組み合わせて、ROMの動作を確認する様子。 CPU本体については、セレクタ、デコーダ、ALUなどの各部品ごとにブレッドボードで組み立てました。なるべく全てのICで動作を確認したあとにはんだ付けに入れるようにしました。 デコーダの動作確認の様子 74HC154と74HC540は代替品を利用した 『CPUの創りかた』は20年以上前に書かれた本であり、出版から一度も改訂されていませ。そのため、書籍内で紹介される部品のうちいくつかはもはや手に入らなくなっています。 私が手に入れることのできなかった部品のうちの1つは、4to16ラインデコーダの74HC154です。調べると、同等の機能を持つICがいくつか見つかりはするため、完全に手に入らなくなってしまったというわけではなさそうなのですが、どうやらこの手のICには相性のようなものがあるらしい?(CMOSとかTTLとか)ため、ほかの手段を取ることにしました。 代わりに私が使ったのは、3to8ラインデコーダ 74HC138 です。こちらであれば、まだ秋月電子でも手に入れることができました。74HC138は3to8とあるように、3ビットの入力から8回路にHとLをマッピングするICです。TD4のROMは16アドレスのため、このままでは1/2の容量しか実装できません。そのため、同じ74HC138を2つ組み合わせることで、この問題を解決しました。 74HC138データシートより引用 74HC138は、1つのイネーブル入力(G1)と、2つのディセーブル入力(G2A、G2B)があります。アドレスの指定に用いた入力4ビットのうち、最上位の1ビットを、一方ではG1に、もう一方ではG2Aに接続し、あまった入力はVccおよびGNDに接続することで、16アドレスに対応できます。最上位ビットがLのとき( 0000 から 0111 まで)1つめのデコーダが有効になり、最上位ビットがHのとき( 1000 から 1111 まで)2つめのデコーダが有効になります。 また、手に入らなかったICの2つめは8回路インバータの74HC540ですが、こちらは6回路インバータ 74HC04 を2つ組み合わせることで簡単に対応できました。4回路余ることになるので、DIPスイッチに繋ぎやすい側の入力を中心に利用し、ほかは全てGNDに接続しました。 キットを使ってはんだ付けの練習をした ブレッドボードでの動作確認ができたためはんだ付けに入りました。はんだ付けの道具には、秋月電子で売っている『はんだ付け入門セット』みたいな名前のものを買いました。 『はんだ付け入門セット』は、 PX-280 というはんだごてと、はんだごて台、吸い取り線、はんだ線などがすべてセットになっているもので、一万円くらいで買えたと記憶しています。一通りマニュアルを読んだ後に『 LED点滅回路はんだ付け練習キット 』を組み立てて、はんだ付けの基本的な練習をしました。 LED点滅回路はんだ付け練習キット ただ、キットはプリント基板で、部品を固定してハンダを流し込むだけで完成するものでした。TD4の製作にはユニバーサル基板を用いたので、ユニバーサル基板における設計の仕方を別途学ぶ必要がありました。そのため、ネットサーフィンをしていたら見つけた 『ユニバーサル基板はんだ付け虎の巻』(まこらぼ) でユニバーサル基板いかんを学びました。 基板を3つに分割して製作した はんだ付けもある程度わかるようになってから、いよいよTD4本体の製作に取り掛かりました。 TD4は上述のキットと比べてはるかに部品数が多く、製作の後半になってから失敗したときに後戻りができなくなるリスクがあると考えました。そのため、第10章に書かれているようにクロックとリセット・ROM・CPU本体の3コンポーネントをそれぞれの基板に分けて実装しました。 これにより、当然ながらパスコンデンサをそれぞれの基板に配置する必要があったほか、ピンソケットとピンヘッダを用いて相互に接続できるようにする必要がありました。 基板はいずれもサンハヤト社のものを用い、クロックとリセットには ICB-503 、ROMには ICB-96PU 、CPU本体には ICB-97U をそれぞれ採用しました(なお、クロックとリセットは後に作り直すことになります)。 基板の選定理由はとくにサイズ以外は気にしていません。ROMにもIC用基板を用いた理由としては、DIPスイッチのすぐ隣にダイオードアレイを配置する関係上、スイッチのランドに連結される形で2ドットあると作りやすかったからことが挙げられます。 FigJamを使って配線のイメージを作った 回路の設計には、専用のCADなどがあることは知っていましたが、FigJamを利用してなんとなくの配線を書いて済ませました。はんだ付けの際にはこれを裏から見る必要があるため、上下左右を間違えないようにこの画面のスクリーンショットを保存し、左右反転した画像をiPadに表示しながら作業していました。 FigJamを使ってCPUの配線を書き込む様子。上部分に部品名のみを書いた回路図を書き、下に実際の画像を置いてそれぞれの配線をマッピングした。 ROMの配線にはポリウレタン銅線(UEW)をたくさん使った TD4を製作する上で最も難しかったのはROMの製作でした。いろいろな人のTD4のレポート記事を読んでいても「難しい」という声が非常に多かったように感じます。特に困難なのが、16個のDIPスイッチの全ての足をそれぞれ結線する点です。DIPスイッチの足8ピン×DIPスイッチの個数16個=128箇所すべてを、隣接するランドで互いに接触することなくはんだ付けしなければいけません。 スイッチの反対側の足にはダイオードアレイが接続されるので、工夫して配線しない限りジャンプする必要があります。『CPUの創りかた』では、紙面の写真を見る限りビニル線を使って製作されているようでしたが、今回は被膜を剥がすのが面倒だったのでポリウレタン銅線(UEW)の0.29mmを使いました。 両端の2つのスイッチを除く14個のスイッチでは、左右のスイッチから伸びてきた線と自身から伸ばす線の2つの線を同じランドに固定する必要があります。そのため、 ポリイミドテープ でUEWを固定してからはんだ付けしました。 ROMの配線。それぞれのスイッチから8本ずつUEWが伸びている。 失敗した点として、UEWの被膜が焼ける温度を誤解してたことがあります。UEWはコテ先にハンダを溜めて、そこにワイヤを通す『はんだメッキ』と呼ばれる方法で被膜を除去します。私が採用したワイヤを含め多くのUEWでは、ウレタン被膜が380℃から400℃で焼けるらしかったのですが、コテの温度を350℃に設定していたため、被膜が十分に焼ききれておらず、途中で作り直す羽目になりました。 ROMの製作を経て、UEWのはんだメッキにおいては『はんだをケチらずにたくさん使う』ことこそがコツだと感じました。 高周波ノイズが発生したため、RC フィルタリングとシュミットトリガを使った 無事に全てのはんだ付けが終わり、実際にROMにプログラムを焼いて(?)動作確認を試みたところ、1Hz/10Hzのクロック周波数において、プログラムカウンタ(レジスタD)の値が1→3→5のように飛び飛びに動作する現象に遭遇しました。ただし、この現象はクロックジェネレータを手動モードに切り替えた際には再現しませんでした。 手動クロックでは動作するという状況から鑑みるに、おそらくCPU本体の側ではなくクロックジェネレータの問題かと考えました。インターネットでいろいろと調査してみたところ『 4bit CPU TD4を動かそう(2) ROM基板と動作確認 | KUNINET BLOG 』という記事で類似の現象に遭遇している事例が報告されており、基板を分割していることが原因ではないかと言及されていまいた。 しかしながら、同ブログ記事で紹介されているようにクロックジェネレータの出力とGNDの間にコンデンサを挟む「 RCローパスフィルタ 」を試しましたが上手くいきませんでした。また『 「CPUの創りかた」を読んで実際に4bitCPUをつくってみた - onbmotorsのメモ 』では、基板を分割しているものの同じ現象には遭遇しておらず、CPU本体の側に原因がある線も捨てきれませんでした。 そこで、なるべく出費は避けたかったですが、やむを得ずオシロスコープを購入し、調査を試みました。オシロスコープは比較的安価な DSO-TC3 というもの試しました。しかし、そのオシロスコープの最小の計測幅である1µsで観測しても、波形はキレイに立ち上がっているように見え、問題は見受けられませんでした。また、同スコープに搭載されているジェネレータ機能を使って、1Hz/10Hzの矩形波を生成してみても、やはりアドレスが不安定に遷移していきました。 オシロスコープでクロックジェネレータの波形を観測した様子。1µsの単位で計測しても、ノイズらしきものは見えなかった。 原因究明は混迷を極めていましたが、やはり手動クロックでは安定して動作することが確認できたので、オシロスコープで観測できない速度の高周波ノイズが入っているのではないかと仮説を立て、ChatGPTの Deep research機能 も使いつつ同様の事例がないか調査しました。 その結果、74シリーズを使って作ったクロック回路で ナノ秒オーダーの高周波ノイズが入っている事例 や、 ナノ秒オーダーのノイズでもフリップフロップが反応していしまう事例 などを見つけることができました。 対処法としてはすでに試したローパスフィルタがあるほか、74HC14を使って作った発振回路をさらに74HC14で2回反転することによって安定させる方法などが紹介されており、この2つを組み合わせることによって1Hz/10Hzの両方で安定して動作するようになりました。 根本原因はよくわかりませんでしたが、同じICでもメーカの差によってこのノイズの有無があるのかと想像しています。ローパスフィルタ単体で解決しなかったことについては、おそらくコンデンサの充電・放電過程でHとLの間の電位に留まるタイミングがあり、シュミットトリガを必要としたのかと想像していますが、詳しいことはわかっていません。 感想 初心者が取り組むにはやや難易度が高かったように思いましたが、大変勉強になりました。特に、応用情報を受験した際に表面上の単語だけ覚えていた「レジスタ」や「プログラムカウンタ」といったモジュールを実際に製作することで、記憶の定着に役立ったように思います。 また、高校数学で出てくるド・モルガンの法則がどのように役に立つのか考えたこともありませんでしたが、カルノー図法と組み合わせてICの数を削減できるとわかったときには感動しました。 引き続き低レイヤーの勉強も続けたいと思っています。次はOSの自作にも取り組んでみたいです。