RISC-Vを目指す
なんとも久しぶりの更新なわけだが、今度のネタは2年半ほど前にやってたCPU作成の続きとなる。前回はオレオレアーキテクチャの4bitCPUだった。今回はそれの32bitへの拡張と、命令セットをRISC-VのRV32Iとして、まともなCPUを作ってみようという企画となる。
そうは言っても2年半の間、回路にはこれっぽっちも触れていなかったのでもう忘れてるし、何も進歩していないということで、果たしてどうなることやら。
RISC-Vとは
リスクファイブ。まあ、適当にぐぐってくださいな。オープンソースで開発されたライセンス料無しで使えるアーキテクチャで、MIPSなどと比べるとディレイスロットが無かったりしてシンプルになっている。賢い人が作っただけにオレオレアーキテクチャよりもずっと回路が作りやすいように考えられているだろう。
アーキテクチャについてはSpecifications - RISC-V Foundationを参照。
WebAssemblyチャレンジ2
とりあえず作ってみた。
WebAssemblyのバイナリフォーマットを見ながらそのまま書いただけなのでさほど難しくない。
LEB128
ちょっと変わっているのはwasm内での値の表現がLEB128というエンコーディングで表現されているところ。これは可変長整数の表現方法で、値は下位7bitで表現して、最上位の1bitが1の場合は次のbyteに続く、という意味になる。1byteで表現できる範囲が127までに減ってしまうが、int32で持っていても入る値はたいがい1桁か2桁程度のことが多いので効率が良い。
デコードは遅くなるがバイナリサイズを小さくすることを優先しているあたり、WebAssemblyがネット上の転送時間を気にしている感じである。
出力データについて
前回の足し算を元ネタとして、必要最低限のセクションのみ出力するようにしてみた。テーブルとメモリのセクションは使っていないので省略して、あとなぜかエクスポートされていたメモリも省略。関数の中身は掛け算にして名称をmulに変更。
ということで11あるセクションのうち4つしか出力していないので短い。あと実行するコードはベタでバイナリ記述になっていて、これを生成するのが最終的な目標になるのだが、そういう技術は持ち合わせていないのでどうなることやら。
プログラムの出力はこんな感じ。
00 61 73 6D 01 00 00 00 01 07 01 60 02 7F 7F 01 7F 03 02 01 00 07 07 01 03 6D 75 6C 00 00 0A 09 01 07 00 20 01 20 00 6C 0B
最後の0x0bは関数の終了で、その前の0x6cが掛け算命令である。前回はここが足し算の0x6aだった。
WebAssemblyチャレンジ
まだ何かができるという状態ではないのだが。
WebAssemblyとは
Apple、Microsoft、Google、Mozillaが力を合わせて開発しているブラウザ用のバイナリフォーマットで、フォーマットっていうか、VMの命令セットと挙動の定義みたいな。バイナリフォーマットはwasmと呼ばれていて、これをブラウザで読み込んで実行することができる。大手ベンダが取り組んでいるのでメジャーなブラウザやブラウザじゃない何かで実行することができるようになるだろう、と言われている。
主な狙いは最近JavaScriptのコードが大きくなっていることに伴うダウンロード、パース、コンパイルの時間短縮で、よく言われる実行速度の向上ではない。んでも最近CやRustで書いたコードをWebAssemly化したらJavaScriptより3倍速くなったという記事が現れて、まあ、そもそも高速な言語なんだからそりゃ速くなるよね、って感じ。今はできないがJavaScriptをコンパイルしてWebAssemly化したら実行速度は言うほど変わらないんじゃないかと思っている。とはいえ高速な言語を高速に実行できるというのはすごく良い。
環境とか
現状ではLLVMでCやRustをLLVM IRに変換→wast(WebAssemblyのテキスト表記。S式)に変換→wasm(バイナリ)に変換とやってJavaScriptで読み込んで実行という手順になる。正式リリース版で実行できるブラウザはこれを書いている今現在ではFireFox52とChrome57。
LLVMよくわかんないしツールいっぱいビルドしたりするみたいなのでそこいらへんは諦めて、うちのChromeで人様の作ったバイナリを実行するぐらいならできるだろう。
準備
Julia で WebAssembly - Qiitaの人が作ったものを拝借する。githubはこちらで、sample.wasmとindex.htmlをダウンロードする。sample.wasmが足し算する関数が入ったバイナリファイルである。こんなの。
00 61 73 6D 0D 00 00 00 01 07 01 60 02 7F 7F 01 7F 03 02 01 00 04 04 01 70 00 00 05 03 01 00 01 07 1C 02 06 6D 65 6D 6F 72 79 02 00 0F 6A 75 6C 69 61 5F 61 64 64 5F 37 31 33 36 30 00 00 0A 09 01 07 00 20 01 20 00 6A 0B
ちなみに最初の4バイトが\0asmとなるのがマジックヘッダで、そのあとの4バイトがバージョン(リトルエンディアン)。このファイルはバージョン0x0dとなっていて、これは開発最終版のバージョンであり、このファイルは正式リリースのバージョン(0x01)とは違うのでChrome57では動かない。動かすためには開発版のChrome Canaryが必要なのだが、そんなもん用意するのも面倒なので、バイナリエディタでおもむろに0x0dを0x01に書き換える。ちなみに開発最終版と正式版はとりあえずこのレベルではフォーマットに違いが無い。と思う。バイナリフォーマットについてはWebAssembly binary encoding version 0x1 - Qiitaや公式を参照。
動かしてみる
index.htmlとsample.wasmを置いたところにRubyのコードを一緒に置いて、
require 'webrick' srv = WEBrick::HTTPServer.new({ DocumentRoot: './', BindAddress: "localhost", Port: 8000, }) srv.start
これを起動してChrome57でhttp://localhost:8000/index.htmlをアクセスすると、
てな感じにAdd!ボタンで足し算ができるようになる。この足し算の計算はWebAssembly側(元ネタを作った人はJuliaで構築したらしい)で行っている。
思ったこと
自分でやったことと言えば0x0dを0x01に書き換えただけなのでぶっちゃけ何もしていないのだが、もうちょい何かやってみたい。LLVMうんぬんでツールチェインを揃えるのはやっぱり面倒で、バイナリフォーマットもたいして難しくないので自前でwasmを出力できる何かを作ったほうが簡単かな〜とか考えているところ。
CustomRenderTargetその5
今回はサンプルのmaptest.rbの話。名前がひどい気味なのはいつもの話なので気にしない。でもさすがにそのうち変えるかも。それはそれとして、動かすとこのような画面が出る。
ちなみに壁との衝突判定は面倒なのでやっていない。外側に出てどこまでも行ける。
CustomRenderTargetその4
初歩的な3Dサンプルということで追加したspheretest.rbだが、実行するとこんな画面が出る。マウスの方向にライトの光源があるっぽい感じにライティング処理が入っている。
今回はこれの話。つってもだらだら書くだけなのでこのへんの記事で3Dが理解できるかというと怪しい。こういう要素があって、こういうことができて、だいたいこんな感じ、みたいなのが把握できればよい、かな。詳しい話はそういうのをきちんと解説する記事がWebにはたくさんあるのでそちらで勉強していただく感じで。