命令セットシミュレータの構想

こんにちは、めのんです!

今年からスタートする新企画について前回お伝えしました。
今回はその新しい企画である「命令セットシミュレータ」について具体的な構想を書いてみることにします。

なぜ命令セットシミュレータを開発するのか?

世の中には主立ったプロセッサの命令セットシミュレータはすでに存在しています。
たとえばGDBのrunコマンドを使えば、ロードモジュールを直接PC上で実行することができます。
ある意味、命令セットシミュレータを開発するのはいわゆる車輪の再開発に当たります。

それでも今回あえてやろうと考えたのは、命令セットシミュレータを作ることで機械語に対する理解が深まるからです。
アセンブリ言語の経験がある方ならそれなりの数がいらっしゃいます。
けれども機械語にしっかり取り組んだ方はそう多くはないのではないでしょうか?

そういうことを踏まえて、もしかしたら何かのお役に立てるかもしれないと考え、今回の企画を立ち上げました。

シミュレーション対象

命令セットシミュレータは機械語をソフトウェア的にシミュレートするプログラムです。
機械語はプロセッサのアーキテクチャごとに異なりますから、対象とするプロセッサを決めないことには始まりません。

対象プロセッサ

今回は現在使われている代表的な8ビットマイコンであるAVRを対象としたいと考えています。
AVRにはたくさん種類がありますので、その中でもArduino UNOで使われているATmega328を対象にします。

さしあたってATmega328のCPUコアだけのシミュレーションを開発し、余力があれば周辺デバイスのシミュレーションもやりたいですね。
でも実機と違って実行速度がどうしても遅くなると思いますので、タイミングに依存するようなものは難しいかもしれません。

参照するドキュメント

ATmega328を対象にすることが決まったところで、今度はその資料を探さなければなりません。
幸いにして有志の方が日本語訳したドキュメントを公開してくださっています。

ドキュメントのタイトルがこれでよかったのかどうかわかりませんけど、とりあえずドキュメントの見出しをそのまま書いてみました。

この2つがあればハードウェアの仕様と命令セットの詳細がわかります。
「命令セット」というのは機械語のボキャブラリーだと考えてください。

実装言語

普通のアプリケーションプログラムと違って、命令セットシミュレータはかなり特殊です。
ですので、実装言語は何でもかまわないとはいきません。

実は実装言語もいくつか検討したんです。
せっかくですので、その検討過程を記録しておきます。
私の知識不足で的外れな結論を出してしまった可能性もありますけど、ここはあえて恥をさらします。

PHP

私が主に使っているスクリプト言語はPHPです。
スクリプト言語の中では一番よくわかっている言語ですので、まっさきにこれを検討しました。

でも、PHPはバイナリーデータの扱いが苦手なんですよね。
バイナリーデータを扱うためのpack、unpack関数というのはあるのですが、単純な配列の要素をランダムアクセスして読み書きするのには使えません。

PHPの配列は連想配列なので単純なバイト列やワード列ではありません。
高機能な分、どうしてもパフォーマンスが落ちてしまいます。

それと、欲しいのは8ビットや16ビットの要素を持つ配列なのに、PHPの配列ではせいぜい32ビットまたは64ビット整数しか要素に持つことができません。

無理矢理PHPで実装できなくもないでしょうけど、ちょっと無理があります。

JavaScript

JavaScriptも実装言語の候補として検討しました。
処理系としてはNode.jsを考えました。

PHPほどではないのですが、JavaScriptもバイナリーデータの扱いが得意ではなさそうです。

ArrayBufferをUint8ArrayまたはUint16Array経由で操作することになると思います。
機能的にはこれで単純な配列と同様にコーディングできるはずです。

でも、十分なパフォーマンスは得られそうにありません。
実測してみると、Cと比べて十数倍遅いことがわかりました。
スクリプト言語なのでCと比べるのは酷なことは当然なんですけどね。

C++

C++は実装言語として問題ないぐらいのパフォーマンスが出せますし、ブログのネタにするのでなければ迷わず選んだかもしれません。

ただ、今回は機械語がどんなものか触れてみたい方を想定読者にしています。
C++が理解できる必要があるとなれば、それだけハードルを上げてしまいます。

そういうこともあって、泣く泣く今回は没にしました。

Zig

以前から私はZigを勉強していました。
かなり面白い言語ですし、パフォーマンス的にも問題ないと思います。

ですが、これもC++と同じで読者のことを考えると不適切です。
おそらくはC++以上にハードルが高いでしょうから。

というわけでZigは没です。
Zigから派生したZenも同様に没です。

Rust

Rustには熱烈なファンが多いのでしょうか?
今回もRustを奨めてくださる方がいらっしゃいました。

おそらくパフォーマンス的にも問題ないでしょうし、私もこれを機会にRustを勉強したいという思いもありました。

けれども、やはりC++やZigと同様の理由で没にしました。

C

となると、最後に残るのはCしかありません。
ごくありきたりな結論に達した感じですね。

Cは文字列処理は苦手ですけど、バイナリーデータの扱いは得意な言語です。
スクリプト言語はその逆ですね。
こんな風にプログラミング言語には得手不得手がありますので、今回の開発はCの得意分野です。

「Cは難しいもの」と決めつけている方もいらっしゃるかもしれません。
けれども、命令セットシミュレータではC特有の難しいコードはほとんど出てこない気がしています。

文法的にもCは多くの言語の元になっています。
C++はもちろん、Java、C#、PHP、JavaScriptなどの経験がある方なら、すんなり理解できるんじゃないでしょうか?

ちょっと難しい書き方をするときは、できるだけ解説を入れたいと考えています。

というわけで、今回の実装言語にはCを使うことに決定しました。


ちょっと長くなってきましたので、今回はいったんここまでにしようと思います。
次回からはATmega328の具体的な内容に踏み込んでいきます。
どうぞご期待ください!