リレー式論理回路シミュレータを自作して1bit CPUまで動かした

- 「1bit CPU」というのは、書籍『CPUの創りかた』に載っている「オリジナルCPU 試作3号機（エレキ式）」のことです。
- ※ ブログに書いていた記事を Qiita に引っ越してきました。元の公開日は 2020-05-03 です。

---

（2025-01-12 追記） Qiita だと GIF画像が表示されないので避難所的に Zenn に転載しました。

https://zenn.dev/sonota88/articles/f914ae1bd17fb5




# 概要

リポジトリ:

https://github.com/sonota88/kairo-gokko

デモ（ブラウザで動かせます）:
https://sonota88.github.io/kairo-gokko/pages/39_aot_compile/index.html
<!-- https://sonota88.github.io/kairo-gokko/pages/39/index.html -->

:::note warn
- 音量を小さめにしていますが、音が出ます
- 表示サイズや負荷の関係でPCブラウザ推奨です
  - とりあえず富豪的に作っていて、まだ最適化などやってません
- 最初は発振するので、スイッチを適当に操作して発振を止める必要があります。止め方については[こちら](https://memo88.hatenablog.com/entry/2020/04/12/094629)を参照してください。
:::



製作過程のメモ（どういうステップを踏んで何を実装していったか、具体的な話はこっちにまとめています）: 

https://memo88.hatenablog.com/entry/2020/04/21/065800

---

動かしている様子です。

:::note warn
（2024-12-21）Qiita の不具合なのか不明ですがアニメgifが表示されないようです。お手数ですが脇のリンクをクリックして表示させてください。

（2025-01-12）[Zenn に転載しました](https://zenn.dev/sonota88/articles/f914ae1bd17fb5) のでそちらで見てください。
:::

![1bit_cpu.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/5a779825-a252-aad1-2aab-7d51fd708363.gif)
[アニメgifが表示されない場合はこちらをクリックしてください](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/5a779825-a252-aad1-2aab-7d51fd708363.gif)

<!--
[f:id:sonota88:20200412074010g:plain]
-->


左下のスイッチがクロックで、右下のスイッチで命令（ `MOV A, A` と `NOT A` ）を切り替えています。

---

回路図を描いて動かすまでの流れ:

- 回路図を LibreOffice Draw で描いて `.fodg` 形式で保存
- fodg ファイルを読んで前処理し、中間データ（JSON）に変換
- シミュレータのプログラムと中間データを使ってブラウザで実行

LibreOffice Draw で描いた回路図はこんな感じ。

<!--
f:id:sonota88:20200411105424p:plain
-->
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/019ed019-3776-f85a-1b1b-19c78cdc5a8a.png)


直線と矩形、矩形内のテキストだけです。部品はグリッドに合わせて配置します。ナナメの配線は禁止。

---

使っている部品:

<!--
- 導線  
  [f:id:sonota88:20200802092432p:plain]
- 電池のプラス極・マイナス極  
  [f:id:sonota88:20200802092519p:plain]
- ランプ  
  [f:id:sonota88:20200802092557p:plain]
- スイッチ。マウスでクリックすると ON/OFF が切り替わります。  
  [f:id:sonota88:20200802092637p:plain]
- リレー（2種類）  
  [f:id:sonota88:20200802093022p:plain]
-->

- 導線  
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/efabd580-0a0f-8416-6f0d-40726d049b25.png)
- 電池のプラス極・マイナス極  
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/6b688ff5-4cba-7f71-97b9-6389c156dfb9.png)
- ランプ  
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/f5f8fb2e-f463-4c52-ca30-3a1524ac5de1.png)
- スイッチ。マウスでクリックすると ON/OFF が切り替わります。  
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/31b10750-be58-028c-f8d7-d7b1171b9232.png)
- リレー（2種類）  
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/bc167c9e-ce38-fa7b-8801-bce4c74a5f95.png)


ランプ、リレーには極性なし（プラス極・マイナス極を入れ替えても動作は変わらない）


---

小さい回路の例をいくつか:

NOT（を3つ繋げたもの）
![not.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/0d1eca62-ac93-db69-6edd-c3231e72d81d.gif)  
[アニメgifが表示されない場合はこちらをクリックしてください](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/0d1eca62-ac93-db69-6edd-c3231e72d81d.gif)


NAND
![nand.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/068b2a43-015f-7c83-b368-fd8a2967ca1f.gif)  
[アニメgifが表示されない場合はこちらをクリックしてください](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/068b2a43-015f-7c83-b368-fd8a2967ca1f.gif)


XOR
![xor.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/9f42f922-272f-800c-2978-47eea147aaba.gif)  
[アニメgifが表示されない場合はこちらをクリックしてください](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/9f42f922-272f-800c-2978-47eea147aaba.gif)


RSフリップフロップ
![rsff.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/34bb8ab3-60ad-679d-2fbf-950164903d1e.gif)  
[アニメgifが表示されない場合はこちらをクリックしてください](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/34bb8ab3-60ad-679d-2fbf-950164903d1e.gif)




----

ほぼ Ruby 製。ブラウザで動かす部分は [DXOpal](https://github.com/yhara/dxopal)  を使っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234055/6902942b-3509-c3f6-46aa-2d96e0380459.png)

（一応残してあるものの）不要になっている部分、補助ツール的なスクリプト、コメントなどを除くと主な部分は 2000行弱（2021-04-11 時点）。途中いろいろありましたができあがってみると意外と小さい。

```
$ wc -l *.rb
  283 child_circuit.rb
  456 circuit.rb
  114 drawer_dxopal.rb
  137 libo_draw.rb
  237 main.rb
   26 preprocess.rb
  307 unit.rb
  346 view.rb
 1906 合計
```

# 製作期間

2019-12-31 〜 2020-02-02
（プロトタイプを作り始めてから 1bit CPU が動くまで）

始める前からいろいろ調べたりはしていて、書き始めたのが 12/31 だったか 12/30 だったか。

回路図エディタの部分を [LibreOffice Draw に丸投げ](https://qiita.com/sonota88/items/4c280ac13b7f7709abeb)することにより、製作期間をかなり短縮してシミュレータ部分に集中することができました。



# どのくらいの電気の知識で始めたか

- 小学校、中学校の理科レベル
  - 電池、エナメル線、豆電球、電磁石、直列・並列つなぎ
- 大学の頃にちょっとだけ電子工作やろうとするも鉱石ラジオ作った程度で終わった
- 『CPUの創りかた』のうっすらした記憶
- リレーは名前は聞いたことあったけどどういうものか知らなかった
- トランジスタの前は真空管を使っていたらしい
- GND って何？

……という程度。




# コンセプト・方針

- ガチャガチャ動く機械仕掛けのおもちゃ
- ピタゴラ装置みたいなの
- 電圧や抵抗は考慮しない
  - 難しそうなので
  - 電気が流れているか、流れていないかだけ考える
- 小学校の理科の工作の延長程度のもの
- なるべく寄り道せずに曳光弾を通す
  - 遅すぎて辛い、ということがなければ最適化は後回し
  - そもそも作れるのか、（論理）回路を動かすには最低限何が必要なのかがよく分かっていなかったので、まずそこをクリアにしたい。他の部分は枝葉。




# なぜ作ったか / 作り始めるまでの経緯

並行してボンヤリと考えていたのですっきりまとめることができませんが、思い出して雑に書き出してみました。

列挙の順序も適当です。



## そもそもは『CPUの創りかた』

https://book.mynavi.jp/ec/products/detail/id=22065

- 最初に読んだのは 4年くらい前
- かなり基本的なところから手取り足取り説明されていてとっても良い本だが、単に読むだけだと後半で分からなくなる
- さすがに何も知らない私みたいなド素人がさらっと読んだだけで理解できるほど甘くはない
- （自分のような初心者は）作りながら読まないと分からないのでは
  - 回路図を読むところがネックになる
  - 回路図というものは抽象化された図なわけで、そこから具体的な回路や動作がどうなるかよく分からない
- しかし作るのは面倒
  - 部品の調達
  - また部屋が散らかる……
  - 知識・経験がなさすぎてゴールが遠い
- 物理CPU作るのは老後の楽しみにしよう……
- とはいえ、先にしくみだけでも理解したい
- しくみを理解するには、やはり自分で作って電子回路についての経験を積む必要があるんだろうな……
  -  → 「しかし作るのは面倒」に戻る
  - ブートストラップ問題
- しくみを理解するだけなら、枝葉の部分を捨ててもっと簡素化してハードルを下げられないか

<!--
  - [vm2gol](https://memo88.hatenablog.com/entry/2019/05/04/232236) のときと似たようなことやってますね

先にしくみを理解してから作りたいが、
しくみを理解するには作らないといけないというループ。
-->

こういうのって、実際に手を動かして作って壊して、回路図とにらめっこしたり計算をやりなおして試行錯誤を繰り返すうちにだんだん勘が養われていくものだと思いますが、そういう経験がない状態なのでなかなか大変です。




## 論理回路シミュレータ

- そもそも論理回路シミュレータというものをよく知らなかった
- シミュレータで CPU（TD4など）を作っている人たちがいると知る
- 物理CPU作る前にこれで試すのは良さそう
  - 手間・時間をかけずに好きなだけスクラップ＆ビルドできる
  - 部屋も散らからない



## nand2tetlis

<!--
- [O'Reilly Japan - コンピュータシステムの理論と実装](https://www.oreilly.co.jp/books/9784873117126/)
-->

https://www.oreilly.co.jp/books/9784873117126/

- 通称（？） nand2tetlis
- 物理的な電子回路でなぜ論理回路が動くのか、という部分がよく分からないまま HDL に進んでしまうのがちょっと不満
- そこの部分のブラックボックス感を解消したいのに




## そもそも論理回路が動くしくみがよく分かってない

- 入力側から電流が流れてきて、それが出力側に伝わるというのは分かる
- NOTゲートってどうなってるの。謎。
  - 入力が L で出力が H になる場合、その H の電力はどこから来てるの
  - 省略されると分からない
- フリップフロップ
  - タイミングが絡んでくるし、入力がループするので、脳内でエミュレートできない
  - （自分で作って）動かしてみないとどうも実感が湧かない
- 論理回路図というものは抽象化された図なわけで、どうすればそれを物理的な回路で実現できるかが分からない


今だからこうやって言語化できていますが、もっとボンヤリとモヤモヤしてました。「なんとなく……分かった気がする……たぶん……とりあえずそういうものだと飲み込んで先に進んでもいいが……（モヤモヤ）」みたいな。

<!--
ここらへんのビルディングブロックのしくみが論理回路、ひいてはコンピュータを作る上である意味根幹なわけで、
理解したいのです。
-->




## リレー

- トランジスタについてもよく分かっていなかったので、トランジスタ → 真空管 → リレー と遡って調べたりしていた
- リレーについて知ることで「要するに何をやっているのか」「何のための部品なのか」が分かった
- 要するに「電気を使ってスイッチを切り替える装置」
  - [英語版 Wikipedia](https://en.wikipedia.org/wiki/Relay) の説明が簡潔で良いです。 "A relay is an electrically operated switch."
  - 「それを早く教えてよ！」という気分に
- リレー、めっちゃ良い。分かりやすい。小学生でも理解できる。電磁石まで知ってればあともう一歩。そのくせインパクトがでかい。
  - 「小学校の理科でついでにリレーまで教えてくれてればよかったのに！」という気分に [^1]
  - 「小学校の理科の知識に、あとはリレーだけ付け加えれば CPU まで作れる」というのは、なんかいい。よくないですか？
- トランジスタについても、「N型 と P型があって正孔が……」という半導体自体の説明よりも、先に役割や目的について着目した方が（自分には）分かりやすかったと思います

たしか、ここがクリアされたことで「あ、これなら自分でも作れるかも？」みたいな気分になった気がします。

[^1]: 指導要領の都合とかでいろいろあるんだと思います

---

（追記 2025-01-11）

> そう、リレーは、電信博物館に置いておくにはあまりにももったいない発明だ。

（『[CODE コードから見たコンピュータのからくり 第2版](https://bookplus.nikkei.com/atcl/catalog/24/02/06/01257/)』 p90）

私もそう思います！





## Minecraft や Oxygen Not Included の論理回路

- 楽しい
- あの要素だけなら、自分でもなんとか作って遊べるのではないか？
  - そう思わせてくれるところがとても良い。教育的。
- グリッド配置にしたのはこれらの影響
- 他にも、マリオメーカーや Cities: Skylines などで作ってみた系の記事や動画を見て「その部分だけ抜き出したもの」程度なら自分でも作れないか、と妄想したり
  - （2010）[スゴすぎ！　「Minecraft」で本物の16ビットコンピュータを再現 - ねとらぼ](https://nlab.itmedia.co.jp/games/articles/1010/01/news094.html)
  - （2015）[【論理演算】マリオメーカーに「3+3=6」を計算させてみた - ニコニコ動画](https://www.nicovideo.jp/watch/sm27235148)
  - （2019）[『Cities: Skylines』でうんちを利用した計算機が制作される。汚水が流れて4ビットの回路を動かす | AUTOMATON](https://automaton-media.com/articles/newsjp/20190718-97734/)



## 水流モデル（失敗）

- 電気について詳しくないので[水流モデル](https://ja.wikipedia.org/wiki/%E6%B0%B4%E6%B5%81%E3%83%A2%E3%83%87%E3%83%AB)の方が分かりやすいかな、と思ってセルオートマトンで作ろうとした
- 逆に複雑で難しかったので中止

<!--
- ただ、これをやっている中で、
  「この、こっち側の配線の分岐してるところから次の分岐まで、
  一瞬で情報が伝わればいいんだけど……ということはグラフ？」
  と気づいたりして知見が深まったので、そこは収穫だった。
-->



# どうやって作るか

- ググっても「論理回路シミュレータの作りかた」なんて解説は出てこない
  - 自分のイメージに一番近かったのがこれ: [A puzzle game that makes us build a complete computer - Joscha Bach](http://bach.ai/a-puzzle-game-that-makes-us-build-a-complete-computer/)
- OSS なシミュレータのソースを読む手もあるが……
  - [Logisim](http://www.cburch.com/logisim/) とか [^2]
  - そんなに本格的なものでなくてよい
  - おもちゃみたいなのでよい
  - 実用目的ではない。いわゆる「教育目的」なもの。枝葉を排して理解しやすさを優先したもの。
  - 自分が作りたかったのは普通の論理回路シミュレータではなく、電池と導線と……で論理回路が動かせる、抽象化されていないシミュレータ
- 結局手探りで
- 詳しくは [製作過程のメモ](https://memo88.hatenablog.com/entry/2020/04/21/065800) の方に書きました


[^2]: 有名っぽいので Logisim を例に出しましたが、Logisim は開発が終わっているようなので他のものを探すのが良さそうです



# 感想

<!--
上で書いたこれが解消できてよかった
  → 「論理回路図というものは抽象化された図なわけで、
  どうすればそれを物理的な回路で実現できるかが分からない」
-->

- おもしろかった！！
- 物理回路と論理回路との接続の部分が分かってよかった
- 1bit CPU を自分で実際に作れてよかった
  - 生まれて初めて（シミュレータ上だけど）CPU を自作した！
  - めでたい！
- NOTゲートえらい
  - NOTゲートが作れるようになるのでリレーは偉大な発明
  - で、リレーで論理回路を作るアイデアはどこから出てきたんだ、誰が始めたんだ……と調べていくとクロード・シャノンにたどり着きます。
    コンピュータの黎明期の話というとチューリングやノイマンが有名ですが、シャノンも非常に重要な仕事をしていたんですね（これも今回いろいろ調べていて知りました）。
      - [中嶋章についてのscivolaさんのコメント](https://qiita.com/sonota88/items/a5d6d3539e0fb8040f74#comment-3fce67595ab213760f79) も参照
    - [連載：インターネット・サイエンスの歴史人物館（2）クロード・シャノン | 情報通信（ICT） | スマートグリッドフォーラム
](https://sgforum.impress.co.jp/article/774)
    - [プログラミングの10大基礎知識（3） | 日経クロステック（xTECH）](https://xtech.nikkei.com/it/free/NSW/ITBASIC/20040403/2/)
- 電気の知識がちょっと増えてよかった
  - ふだんやらないことをやると知らないことだらけで楽しい
- むちゃくちゃ難易度高いということもなく、動くと楽しいのでプログラミングのお題としてもおもしろいと思います。おすすめ。

---

あと、yhara さんとささださんに拾ってもらえた :pray: ので満足度がとても高まりました。


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">DXOpal使用事例が！ <a href="https://t.co/trmR22dWBf">https://t.co/trmR22dWBf</a></p>&mdash; yhara (Yutaka HARA) (@yhara) <a href="https://twitter.com/yhara/status/1289932050598780928?ref_src=twsrc%5Etfw">August 2, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">リレー式論理回路シミュレータを自作して1bit CPUまで動かした - memo88 <a href="https://t.co/oH4ud7abUl">https://t.co/oH4ud7abUl</a></p>&mdash; _ko1 (@_ko1) <a href="https://twitter.com/_ko1/status/1289761803518398465?ref_src=twsrc%5Etfw">August 2, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 




# TODO

気が向いたらやりたい

<!--
スイッチの効果音
-->

- 最適化・リファクタリング
  - 現状ではだいぶ富豪的なので
- タイミングチャート付ける
  - そんなに難しくなさそう
  - (2020-07-26) [付けました
    ](https://memo88.hatenablog.com/entry/2020/07/26/140308)
- 1bit CPU から先
  - これ以上規模が大きくなると大変そうだし、論理回路と物理回路の接続の理解についてはだいぶ気が済んだので、続きを作るとしたら既存の論理回路シミュレータを使えばよさそう
- オブザーバーパターンや Actor モデルを使って書くとよさそう？
  - （追記）呼び出しの連鎖が止まらなくなるのでオブザーバーパターンではダメ



# 関連

今のところ直接関連するというわけではないですが、もっと上のレイヤーの話ということで。1bit CPU と下記の VM の間のギャップも埋めていければなあと考えてはいます。

- [RubyでオレオレVMとアセンブラとコード生成器を2週間で作ってライフゲームを動かした話](https://memo88.hatenablog.com/entry/2019/05/04/232236)
- [Rubyで素朴な自作言語のコンパイラを作った](https://memo88.hatenablog.com/entry/2020/05/04/155425)




# 作った後に読んだもの

- 川添愛 [【東京書籍】 一般書籍 文芸 コンピュータ、どうやってつくったんですか？](https://www.tokyo-shoseki.co.jp/books/81189/)
  - 2020-12 に読んだ。リレーで説明されてて良い。
- 上原周 [作ろう！CPU | マイナビブックス](https://book.mynavi.jp/ec/products/detail/id=116654)
- Charles Petzold [CODE コードから見たコンピュータのからくり 第2版 | 日経BOOKプラス](https://bookplus.nikkei.com/atcl/catalog/24/02/06/01257/)
  - 2024年に読んだ
  - Intel 8080 のサブセットを作る
- (2025) [Rubyで作る論理回路シミュレータの設計の話 - Kashiwa.rb #12 - Speaker Deck](https://speakerdeck.com/kozy4324/rubydezuo-rulun-li-hui-lu-simiyuretanoshe-ji-nohua-kashiwa-dot-rb-number-12)




# 他に Ruby 関連で書いたもの

https://memo88.hatenablog.com/archive/category/Ruby