Slide 1

Slide 1 text

Ruby で作る RISC-V CPU エミュレーター hachi 2025/05/10

Slide 2

Slide 2 text

目次 ● 大阪府交野市在住 Rubyist ● 低レイヤーエケチェン ○ 京都の?大学で電気電子工学 を修めたんだが… ● Kernel/VM探検隊は初参加です ● 初参加初登壇を選んだことをちょっ と後悔しています hachi (@hachiblog)

Slide 3

Slide 3 text

なんで Ruby で? 作って意味ある?🤔

Slide 4

Slide 4 text

まあ聴いてくれ

Slide 5

Slide 5 text

2025年3月初旬

Slide 6

Slide 6 text

技術書典18サークル応募

Slide 7

Slide 7 text

技術書典18サークル応募

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

実践で学ぶ基本情報を テーマにしてみるか

Slide 10

Slide 10 text

基本情報技術者試験の本をちょっと読む

Slide 11

Slide 11 text

基本情報技術者試験 ● 基本 ● 大学の時やったなぁみたいな内容が結構出てくる ○ データ構造 ○ アルゴリズム ○ ネットワーク ○ etc ● マイナスの数の表し方とかも出てくる ○ 1の補数、2の補数 ○ 2の補数を一般的には使っていることが多い

Slide 12

Slide 12 text

なんで2の補数がいいんだっけ

Slide 13

Slide 13 text

作ってみればわかるか?

Slide 14

Slide 14 text

CPU作ってみるかー

Slide 15

Slide 15 text

ちなみに

Slide 16

Slide 16 text

ちなみに

Slide 17

Slide 17 text

自分の前提知識 ● 高校生ぐらいの時に書籍 「CPU の創りかた」を買って放置する ● 大学2年生ぐらいの時に実験でロジックICを組み合わせてなんか作る課題 ○ 全然記憶ない ● 大学4年生ぐらいの時に実験でFPGAでなんかCPUみたいなものを作った気がす る ○ これは結構楽しかった

Slide 18

Slide 18 text

自分の前提知識 ● 高校生ぐらいの時に書籍 「CPU の創りかた」を買って放置する ● 大学2年生ぐらいの時に実験でロジックICを組み合わせてなんか作る課題 ○ 全然記憶ない ● 大学4年生ぐらいの時に実験でFPGAでなんかCPUみたいなものを作った気がす る ○ これは結構楽しかった つまりほぼ無い

Slide 19

Slide 19 text

早速作っていこう

Slide 20

Slide 20 text

前提知識

Slide 21

Slide 21 text

CPUエミュレーター

Slide 22

Slide 22 text

一般的なCPU(エミュレーター)の構成 レジスタ CPU デコーダ 演算器 メモリ

Slide 23

Slide 23 text

一般的なCPU(エミュレーター)の動き①フェッチ レジスタ CPU デコーダ 演算器 メモリ Program Counter 0x34202f73 0x800001a0

Slide 24

Slide 24 text

一般的なCPU(エミュレーター)の動き②デコード レジスタ CPU デコーダ 演算器 メモリ 0x34202f73

Slide 25

Slide 25 text

一般的なCPU(エミュレーター)の動き②デコード レジスタ CPU デコーダ 演算器 メモリ 0x34202f73 34202f73

Slide 26

Slide 26 text

一般的なCPU(エミュレーター)の動き②デコード レジスタ CPU デコーダ 演算器 メモリ 0x34202f73 34202f73 110100001000000010111101110011

Slide 27

Slide 27 text

一般的なCPU(エミュレーター)の動き②デコード レジスタ CPU デコーダ 演算器 メモリ 0x34202f73 4c771663 1001100011101110001011001100011 bne a4,t2,8000066c

Slide 28

Slide 28 text

一般的なCPU(エミュレーター)の動き③実行 レジスタ CPU デコーダ 演算器 メモリ bne a4,t2,8000066c

Slide 29

Slide 29 text

一般的なCPU(エミュレーター)の動き③実行 レジスタ CPU デコーダ 演算器 メモリ bne a4,t2,8000066c a4,t2

Slide 30

Slide 30 text

一般的なCPU(エミュレーター)の動き③実行 レジスタ CPU デコーダ 演算器 メモリ bne a4,t2,8000066c a4,t2 8000066c Program Counter

Slide 31

Slide 31 text

RISC-V(リスクファイブ) ● オープンソースの命令セットアーキテクチャ ● RISC(reduced instruction set computer) というように基本の命令セット数が少な い ● 現状PC の CPU としての事例はまだ少なく、マイコンや特定の用途が多い

Slide 32

Slide 32 text

RISC-V(リスクファイブ) ● オープンソースの命令セットアーキテクチャ ● RISC(reduced instruction set computer) というように基本の命令セット数が少な い ● 現状PC の CPU としての事例はまだ少なく、マイコンや特定の用途が多い

Slide 33

Slide 33 text

RISC-V(リスクファイブ) ● オープンソースの命令セットアーキテクチャ ● RISC(reduced instruction set computer) というように基本の命令セット数が少な い ● 現状PC の CPU としての事例はまだ少なく、マイコンや特定の用途が多い

Slide 34

Slide 34 text

今回作るもののスコープ

Slide 35

Slide 35 text

今回作るもののスコープ add 命令テストが pass する

Slide 36

Slide 36 text

今回作るもののスコープ add 命令テストが pass する

Slide 37

Slide 37 text

実装した命令 ADD ADDI LUI AUIPC 算術演算 SW ストア JAL ジャンプ &リンク SLLI シフト ORI 論理演算 ECALL 環境 CSRRS CSRRW CSRRWI CSR BEQ BNE BLT 分岐

Slide 38

Slide 38 text

実装方針 ● とりあえず基本のレジスタ、メモリ、デコーダあたりを作る ● テストを実行する ● 実行不可能な命令が来たら例外を吐く ○ 実装する ● テストが通る!

Slide 39

Slide 39 text

実装方針 ● とりあえず基本のレジスタ、メモリ、デコーダあたりを作る ● テストを実行する ● 実行不可能な命令が来たら例外を吐く ○ 実装する ● テストが通る!

Slide 40

Slide 40 text

実装 ● RISCV32CPU class を作成 ● load_program method でプログラムをメモリに読み込む ● execute method でプログラムを実行

Slide 41

Slide 41 text

実装 ● RISCV32CPU class を作成 ● load_program method でプログラムをメモリに読み込む ● execute method でプログラムを実行

Slide 42

Slide 42 text

実装

Slide 43

Slide 43 text

実装

Slide 44

Slide 44 text

実装

Slide 45

Slide 45 text

実装 これだけ!

Slide 46

Slide 46 text

実装

Slide 47

Slide 47 text

苦労したポイント①テスト用バイナリの作成 ● riscv-tests は自分でコンパイルする必要がある ○ Apple Silicon では結局うまくいかなかった ○ Docker on rosetta2 も撃沈 ○ 結局 Linux 機を引っ張り出してくるとすんなり実行できた

Slide 48

Slide 48 text

苦労したポイント①テスト用バイナリの作成 ● riscv-tests は自分でコンパイルする必要がある ○ Apple Silicon では結局うまくいかなかった ○ Docker on rosetta2 も撃沈 ○ 結局 Linux 機を引っ張り出してくるとすんなり実行できた

Slide 49

Slide 49 text

苦労したポイント②RubyのIntegerの扱い ● Rubyの Integer は多倍長整数 ● 一方で RISC-V で扱える数は 32bit が最大 ○ 符号拡張 ○ オーバーフロー

Slide 50

Slide 50 text

苦労したポイント②RubyのIntegerの扱い ● Rubyの Integer は多倍長整数 ● 一方で RISC-V で扱える数は 32bit が最大 ○ オーバーフロー ○ 符号拡張 0b100 -> 8

Slide 51

Slide 51 text

苦労したポイント②RubyのIntegerの扱い ● Rubyの Integer は多倍長整数 ● 一方で RISC-V で扱える数は 32bit が最大 ○ オーバーフロー ○ 符号拡張 0b100 -> 8 0b100 -> -4

Slide 52

Slide 52 text

苦労したポイント②RubyのIntegerの扱い ● Rubyの Integer は多倍長整数 ● 一方で RISC-V で扱える数は 32bit が最大 ○ オーバーフロー ○ 符号拡張 0b100 -> 8 0b100 -> -4 2147483648 + 32768 = 2147516416

Slide 53

Slide 53 text

苦労したポイント②RubyのIntegerの扱い ● Rubyの Integer は多倍長整数 ● 一方で RISC-V で扱える数は 32bit が最大 ○ オーバーフロー ○ 符号拡張 0b100 -> 8 0b100 -> -4 2147483648 + 32768 = 2147516416 2147483648 + 32768 = 32768

Slide 54

Slide 54 text

ということで無事実装完了 🎉

Slide 55

Slide 55 text

良かった点 ● 曲がりなりにもバイナリが読めるようになった ● 簡単にとりあえず動くCPUが作れた ● 慣れ親しんだ Ruby で実装できた

Slide 56

Slide 56 text

良くなかった点 ● Ruby の Integer は多倍長整数なので 32bit にわざわざ制限してやる必要がある ので面倒 ● HDL ほどハードウェアに寄ってないので実際どう配線するんだ?みたいなところは わからない

Slide 57

Slide 57 text

まとめ ● Ruby で riscv-tests の add 命令のテストが通る CPU エミュレーターを作った ● 簡単に CPU の仕組みがまなべるよ(足りないところはたくさんあるので許して ● みんなも好きな言語でやってみてね ● Next Step は bootloader が動くところまで作りたい

Slide 58

Slide 58 text

なんで Ruby で? 作って意味ある?🤔

Slide 59

Slide 59 text

なんで Ruby で? 作って意味ある?🤔

Slide 60

Slide 60 text

なんで Ruby で? 作って意味ある?🤔 俺にとってはある!

Slide 61

Slide 61 text

ご清聴ありがとうございました

Slide 62

Slide 62 text

出典 ● RISC-V原典 ● コンピュータの構成と設計 ● The RISC-V Instruction Set Manual