Slide 1

Slide 1 text

Rubyで作る論理回路シミュレータ CPUを理解したくてDSLを創った話 の設計の話 2025.6.19 Kashiwa.rb #12 Koji NAKAMURA (@kozy4324)

Slide 2

Slide 2 text

Koji NAKAMURA ● 𝕏: @kozy4324 ● GitHub:@kozy4324 ● Classi株式会社所属 ● Kashiwa.rb主催 自己紹介

Slide 3

Slide 3 text

デモ

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

作ったもの: logicuit ● logi(c cir)cuit -> logicuit ● 電気回路シミュレータ ● 書籍「CPUの創りかた」を理解したくて作った ● https://www.amazon.co.jp/dp/4839909865/

Slide 6

Slide 6 text

この発表でお話しすること ● 「論理回路のモデリング」と「内部DSLの設計」をどういった道 筋でやったのかという話 ● 作ったものは小さいのだけれどそれなりに試行錯誤したという 話

Slide 7

Slide 7 text

この発表の楽しみ方 ● 「自分ならこうモデリングするだろう」「こう設計するだろう」とい うのを考えながら聞いてもらえるといいかもしれない ○ モデリングや設計は唯一解があるものでもないと考えてい ます(要件や制約にもよるものではあるけど) ○ 「自分ならこうする」というフィードバックがもらえるとむしろ 嬉しい

Slide 8

Slide 8 text

作り始め初期フェーズ

Slide 9

Slide 9 text

前提状態 ● 書籍を1周ちょうど読み終えてRubyでコード書いてみるかと思 い立ったタイミング ● 対象(コードで表現しようとしているもの)のイメージがぼんやり とあるだけ

Slide 10

Slide 10 text

最初に設計指針は決めた ● 最優先事項は CPUの仕組みを理解すること ○ 自分の認知に寄り添う形で論理回路を論理回路らしく設計 すること とも表現できる ● 逆に優先しないこと ○ CPUや論理回路の理解に寄与しない設計の追求 ○ 処理速度や効率的な処理実行の最適化

Slide 11

Slide 11 text

まず 論理回路らしいとは? の解像度を上げる A B Y AND A Y NOT and more…

Slide 12

Slide 12 text

ゴールはこれ

Slide 13

Slide 13 text

基本論理ゲートの一つを眺めてみる A B Y AND A B Y AND Bをon Bをoff ● どこに電流が流れているかを 状態 として表現する? ● 出力Yは入力A,Bの射影とも言えそう → 関数型の機運?

Slide 14

Slide 14 text

電流は「流れる」もの ● 左の入力Bをonにすると右の出力Yに伝播されてほしい ● コレってストリーム?リアクティブプログラミング?? A B AND Y AND

Slide 15

Slide 15 text

こーゆーのもある: Dフリップフロップとクロック ● 入力 D の値をクロック立ち上がり時に Q 出 力に保持する ● 1ビットの状態を記憶可能 ● つまり CPU の「レジスタ」になるやつ ● \(状態)/ CK

Slide 16

Slide 16 text

さて、どうしよう? (ここでシンキングタイム)

Slide 17

Slide 17 text

私の選択「まずは素朴でええやろ」 ● 悩んだら素朴な方法を選択する ● 困るまで素朴な方法で頑張る

Slide 18

Slide 18 text

素朴なモデリング(1) ● Ruby なので OOP を選択 ● Signal クラス ○ 電流が流れる単位の信号 ○ #current: true | false ○ #on / #off ● Gates::And クラス ○ has many Signal(s) A B Y AND

Slide 19

Slide 19 text

素朴なモデリング(1) ● 入力A/Bの状態(#current)が変化 するたびに出力Yを評価する (#evaluate) A B Y AND #evaluate

Slide 20

Slide 20 text

擬似コード(1)

Slide 21

Slide 21 text

素朴なモデリング(2) ● AND(1)の出力YとAND(2)の入力Bは接続している ● Yの@downstreamにBが入っている ● Yの値が変わったらBに値を伝播するだけ A B AND(1) Y AND(2) A Y B

Slide 22

Slide 22 text

擬似コード(2)

Slide 23

Slide 23 text

擬似コード(2)

Slide 24

Slide 24 text

素朴なモデリング(3) ● フリップフロップはクロック立ち上がり時に入 力Dで出力Qを評価する ● Clock クラス ○ #connects_to(component) ○ #tick ■ #connects_toで接続したもの全てを 再評価する CK

Slide 25

Slide 25 text

擬似コード(3)

Slide 26

Slide 26 text

擬似コード(3)

Slide 27

Slide 27 text

擬似コード(3)

Slide 28

Slide 28 text

クロックはシングルトンにした ● 同じタイミングで信号が送られる ○ =同じタイミングで処理したい ● 1回路に1クロックあれば良さそう ○ 少なくとも書籍が説明する範囲の 回路においては CK D Q CK D Q

Slide 29

Slide 29 text

ここまでで作ったクラス群 Signal #connects_to(other) #on #off Clock #connects_to(comp) #tick And Or Not and more…

Slide 30

Slide 30 text

DSL設計フェーズ

Slide 31

Slide 31 text

ANDゲートの実装

Slide 32

Slide 32 text

ORゲートとの実装差分

Slide 33

Slide 33 text

部品と部品を繋げて組み合わせる実装

Slide 34

Slide 34 text

部品と部品を繋げて組み合わせる実装

Slide 35

Slide 35 text

DSLを創るモチベーション ● 各部品をもっとシンプルに宣言的に定義したい ● 部品と部品を組み合わせてより複雑な部品を作り上げること を実現したい ○ その際のコード記述による認知負荷は極力下げたい ● 直感的に理解できるコード記述であって欲しい ○ 少なくとも自分にとっては

Slide 36

Slide 36 text

さて、どうしよう? (2回目のシンキングタイム)

Slide 37

Slide 37 text

部品を定義するDSL: ANDゲート

Slide 38

Slide 38 text

部品を定義するDSL: ORゲート

Slide 39

Slide 39 text

部品を定義するDSL: Dフリップフロップ

Slide 40

Slide 40 text

部品を定義するDSL: Dフリップフロップ inputsに clock: :ck を含めるとSequential な 部品となり、クロック信号を受け取るごとに outputsを評価するようになる

Slide 41

Slide 41 text

部品を組み立てるDSL: 半加算器

Slide 42

Slide 42 text

部品を組み立てるDSL: 半加算器 connects_to の alias で >> メソッドを導入 この部品とこの部品を繋げているよ〜を記号的に表現している

Slide 43

Slide 43 text

これを組み立てる

Slide 44

Slide 44 text

CPU実装の一部分: 読み解くには少しツラい...

Slide 45

Slide 45 text

1Signal=1bit、4bit でまとめて部品を繋げたい イミディエイトデータ 0000 入力ポート 出力ポート データセレクタ Aレジスタ Bレジスタ 出力ポート プログラムカウンタ SELECT A SELECT B A B C3 C2 C1 C0 ALU LD0 LD1 LD2 LD3 書籍にある図を引用 概念的にも4bitでまとめて扱いたい

Slide 46

Slide 46 text

最終形: 多対多の接続を可能にした

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

まとめ

Slide 49

Slide 49 text

まとめ(1) ● モデリングと実装において困るまでは素朴な方法で進もうとい う選択をしたが、大きな困りごとに遭遇することなくゴールまで 作り切ることができた ○ 実は途中でシグナルの伝播で頭を悩ませる問題もあった が、うまい解決策を見つけられて事なきを得ている ● 素朴なモデリング・素朴な実装でも割とうまくいくものですよ ねっていうのが今回伝えたかった事の一つ

Slide 50

Slide 50 text

まとめ(2) ● (自分の中では)なかなか論理回路を論理回路らしく表現する 実装が実現できたと思っている ● Rubyで内部DSLを設計・実装して何かしらの問題領域に取り 組むのって楽しいですね! ○ Ruby力が試されている気がする ○ これがもう一つの伝えたかったこと

Slide 51

Slide 51 text

リポジトリ URL https://github.com/kozy4324/logicuit

Slide 52

Slide 52 text

EOF