undefined

bokuweb.me

ファミコンのエミュレータをRust / WebAssembly で書き直した

f:id:bokuweb:20180208090512p:plain

概要

以前、JSで書いた(ファミコンのエミュレータを書いた - undefined)ファミコンのエミュレータをRustで書き直してみた。 また、技術的な内容はQiitaの方にも書いているので興味のある方は参照してみてください。(まだ Hello, World!までしか書けてませんが。)

qiita.com

もともとファミコンのエミュレータって新しい言語を習得するのにちょうどいい題材だったりするのでは、って話しからスタートしてて、よくわからないのでJSで書いてみて、ようやくRustで一通りは実装できた感じ。まだバグや未実装(音声周りやマッパー)も多いんですが、ひとまずはお腹いっぱいな感じ。

成果物

github.com

あと、いくつかのROMは以下で遊べるようにしてます。音が出るので注意してください。 またAPUの実装にまだバグが残っているのDCMチャンネルが未実装なので音が変だったり出てなかったりします。 描画のほうはマッパー0であれば、ほぼほぼ問題ないと思ってます。

また、現状chromeでのみ動きます。firefoxは(多分)esmodulesのフラグを立てれば動きます。

https://bokuweb.github.io/rustynes/

CPUやPPUやRAM / ROM周りをRustで書いて、描画や音はemscriptenを介してJS側でcanvas / WebAudioのAPIを叩くようにしています。 これに着手し始めたときは、wasm32-unknown-emscripten しか選択肢がなかったのですが、今なら、wasm32-unknown-unknown が選択できます。 今から着手するなら、wasm32-unknown-unknown 前提で、stdwebwasm-bindgen辺りを使用しemscriptenを剥がしたほうが良い面が多いような気がします。

過程

移植するだけなので強くてニューゲーム気分だったんですが、駄目ですね。 前回よりわけの分からない状態は減ったものの、それでもおかしなバグには遭遇しました。

Hello world

ここまでは、とにかくコンパイラに怒られまくったりどうやってブラウザで描画するのがいいのか悩んだりで大変でした。Qiitaかどこかにも書きましたがHello, World!を表示するにはCPUがほぼほぼ実装できていないといけないのでやはりここまでは苦労しますね。

GIKO005

スプライトを表示するサンプル。Hello, Worldからここまではすんなり。

GIKO016

スクロールが絡んでくるとやはりよくわからないこと現象に遭遇する

GIKO017

前回対応していなかった8 * 16形式のスプライトに対応した、が、ばぐってて歩く度に顔が上下するキャラクターが産まれてしまった。

Super mario bros

さすがにハマりどこは抑えてたので着手後早い段階でそこそこ描画されてた。

思わぬところがスクロール

隠しブロックが隠れてない

土管が仕事しない

音の伸びが良すぎる このバグまだ解決できてなくて、地下でブロック叩いたときになんとも言えない音が鳴る

falling

f:id:bokuweb:20180208090512p:plain

今回見つけた謎のROM。ひたすらおっさん(?)が落ちていくゲーム。 実はオープンソースで、initial commitが2018年の1月7日になっている。

github.com

つまり2018年産まれのファミコンROMということになる。タイトルの音楽が好きだったりする(ちょっとAPUの実装の都合でおかしいとこありますが)

速度

WebAssemblyというと速度が気になると思います。JS版との比較を行ってみました。 WebAudio周辺は共通かつJSは側の処理なので比較はAPUをディセーブルにして、giko017.nesでメインループの処理時間20回分の平均値を取っています。マシンはMacBook Air (11-inch, Early 2015) , 1.6 GHz Intel Core i5, 8 GB 1600 MHz DDR3

ブラウザ JS版 Wasm版
Chrome 63 4.36ms 5.68ms
Firefox 58 5.76ms 3.98ms
Safari 11 9.98ms 4.21ms

Firefox, Safariではwasmのほうが速かったんですが、chromeではJS版の方が速くwasm版はイマイチでした。emscriptenのグルーコードのオーバーヘッドやrust / wasm周りに不備、チューニング不足も当然あるでしょうが、firefoxでそこそこ速いこと考えると、v8すごいって話しとchrome x wasmはまだまだってことになるんでしょうか。このあたり正直なところよくわかってないです。

さいごに

まだ未実装箇所やバグも多いんですが、お腹いっぱいなのでひとまずここまでにして、何か次に取り掛かりたいなーという思い。 一応Rustで書いたものの、分からないことだらけでもう少し、いろいろ書いてみないとなーという気持ち。

なにかおかしなことしてたらプルリクエストなどいただけると泣いて喜びます

題材としては、以前お世話になったARM7のエミュレータを書いてみるとか、ラズパイにOSを移植してみるとかが楽しそうだなーと思いつつ、goも勉強したいので時間はかかりそうです。