elvm-cpuを作った話

この記事はseccamp2017 Advent Calendar 2017 - Adventarの24日目の記事です!
これまた素人記事なので間違え有ったらご指摘お願いします!

自作CPUってなんだ

まずこれです。僕はこれすら分かっていなくて苦労しました。

基本の流れ

命令を読み取る

デコードする

実行する

の繰り返しだと思います。
verilog等のハードウェア記述言語で書いていきます。
回路は勝手に生成してくれるので割とソフトウェアっぽく書くことが出来ます(感想)
最小構成は
GitHub - zuvizudar/td4
が分かりやすいと思います。(「CPUの創りかた」のTD4のverilog実装です)

デコード

f:id:zuvizudar:20171224123526p:plain (命令フォーマットの例)

読み取った命令を分解します。
(このブログ毎回分解してる気が、、w)

//td4の場合、op4bit,im4bitの構成
assign im=dout[3:0];
assign op=dout[7:4];

実行

case(op)
    4'b0000:begin
        a<=a+im; //add 
    end
   (略)
endcase

elvm-cpu

流れは掴んで貰えたでしょうか?

次は僕がセキュキャンで作ったCPUの紹介です。

その名も「elvm-cpu」!
github.com

そのまんまの命名ですね。。w

設計思想?

当初の考えとしてはc言語が動くcpuを作りたい!というものです。

アセンブリと対応する命令セットを書けば良いのかな?とか考えていました。

そんな時「ELVMというのがあるよ」と教えてもらいました。

ELVM

EsoLang Virtual Machineの略で、C言語で書かれたプログラムをELVM IRという中間形式に変換した後に、それを元に多言語にトランスパイルするものです。
GitHub - shinh/elvm: EsoLangVM Compiler Infrastructure

つまり、elvmにcpuのバックエンドを追加すれば、

c → elvm ir → elvm-cpuの命令  

と言った感じに生成されます。

バックエンドの書き方はcのバックエンドを参考にしました。(c → elvm ir → c というのもあるんです)

これの良さは命令が21種類しか無いこと、頑張ってアセンブリを命令に落とし込むコードをゴリゴリ書く必要が無くなったことです。

様子

なんということでしょう!
なんの変哲もないhello,worldコードが

int main() {
  const char* p = "Hello, world!\n";
  for (; *p; p++)
    putchar(*p);
  return 0;
}

80個のelvm-cpuの命令に大変身!?

1_00100_00000000_000_0_01001000 //mem[0b00000000]に0b1001000(=72='H')をstore!
1_00100_00000001_000_0_01100101
.
.
(略)

(命令フォーマットの詳細はgithubのREADMEに載せてます。興味があれば!)
実行!(rs232c出力)
f:id:zuvizudar:20171224234336j:plain:w400

あとがき

cpu全然分かってないのでこれから勉強していきたいです。
パタヘネ本とか読みたい、、